;;; -*- Mode: Lisp; Package: EDITOR -*-
;;; ggrep.l

;; Copyright (C) 2001-2005 OHKUBO Hiroshi <ohkubo@s53.xrea.com>

;; Author: OHKUBO Hiroshi <ohkubo@s53.xrea.com>
;; Time-stamp: <2005/10/08 12:22:19 +0900>

;;; Commentary:

;; Description:
;;
;;  Grep 椶帡偺峴巜岦専嶕傪峴偄傑偡丅
;;
;;    仩専嶕曽朄
;;    丒暋悢専嶕僷僞乕儞巜掕 AND/OR 専嶕
;;    丒堦抳/晄堦抳専嶕
;;    丒僶僢僼傽/僼傽僀儖扨埵峣崬傒専嶕
;;        - 慜夞儅僢僠偟偨僶僢僼傽/僼傽僀儖偑嵞専嶕偺懳徾
;;    丒峴扨埵峣崬傒専嶕
;;        - 慜夞儅僢僠偟偨峴偑嵞専嶕偺懳徾
;;        - 専嶕僷僞乕儞偑暋悢峴偵搉偭偰儅僢僠偡傞応崌偱傕峣崬傒専嶕壜擻
;;    丒僄儞僐乕僪巜掕専嶕 (僼傽僀儖)
;;    丒僔儞僞僢僋僗巜掕専嶕 (僶僢僼傽)
;;
;;    仩専嶕懳徾
;;    丒僇儗儞僩僶僢僼傽巜掕専嶕
;;    丒慡昞帵僶僢僼傽巜掕専嶕
;;    丒暋悢僨傿儗僋僩儕巜掕専嶕
;;    丒暋悢僼傽僀儖巜掕専嶕
;;    丒惓婯昞尰偱偺暋悢僶僢僼傽巜掕専嶕
;;
;;    仩弌椡曽朄
;;    丒僶僢僼傽/僼傽僀儖柤丄峴斣崋側偟偺弌椡
;;    丒僶僢僼傽/僼傽僀儖柤偺傒偺弌椡
;;    丒僼儖僷僗柤偱偺弌椡
;;
;;    仩専嶕愝掕偺曐懚
;;    丒専嶕忦審愝掕偺曐懚丄撉崬丄嶍彍(僟僀傾儘僌巊梡帪)
;;
;;    仩採嫙僐儅儞僪
;;    劕劒劒劒劒劒劒劒劧劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劖
;;    劔僐儅儞僪柤    劆僷僞乕儞劆懳徾              劆懳徾(C-u)       劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆愢柧                                          劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep         劆惓婯昞尰劆僶僢僼傽儕僗僩    劆僇儗儞僩僶僢僼傽劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆AND/OR 専嶕                                   劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔fggrep        劆暥帤楍  劆僶僢僼傽儕僗僩    劆僇儗儞僩僶僢僼傽劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆AND/OR 専嶕                                   劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep-and     劆惓婯昞尰劆僶僢僼傽儕僗僩    劆僇儗儞僩僶僢僼傽劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆AND 専嶕                                      劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔fggrep-and    劆暥帤楍  劆僶僢僼傽儕僗僩    劆僇儗儞僩僶僢僼傽劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆AND 専嶕                                      劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep-or      劆惓婯昞尰劆僶僢僼傽儕僗僩    劆僇儗儞僩僶僢僼傽劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆OR 専嶕                                       劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔fggrep-or     劆暥帤楍  劆僶僢僼傽儕僗僩    劆僇儗儞僩僶僢僼傽劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆OR 専嶕                                       劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep-narrow  劆惓婯昞尰劆grep 寢壥僶僢僼傽 劆                劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆峣崬傒専嶕(僶僢僼傽偐傜偼峴斣崋忣曬偺傒庢摼)  劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔fggrep-narrow 劆暥帤楍  劆grep 寢壥僶僢僼傽 劆                劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆峣崬傒専嶕(僶僢僼傽偐傜偼峴斣崋忣曬偺傒庢摼)  劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔xggrep        劆惓婯昞尰劆僨傿儗僋僩儕      劆                劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆暋悢僨傿儗僋僩儕巜掕専嶕                      劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔zggrep        劆惓婯昞尰劆僼傽僀儖          劆                劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆暋悢僼傽僀儖巜掕専嶕                          劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep-contents劆惓婯昞尰劆僇儗儞僩僶僢僼傽  劆巜掕僶僢僼傽    劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆峣崬傒専嶕(巜掕僶僢僼傽撪僐儞僥儞僣偺傒偱専嶕)劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep-buffer  劆惓婯昞尰劆僇儗儞僩僶僢僼傽  劆巜掕僶僢僼傽    劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆ggrep / ggrep-narrow / ggrep-contents         劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep-detail  劆        劆                  劆                劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆minibuffer 偐傜慡偰傪巜掕偟偰専嶕             劔
;;    劙劒劒劒劒劒劒劒劰劒劒劒劒劧劒劒劒劒劒劒劒劒劒劧劒劒劒劒劒劒劒劒劜
;;    劔ggrep-dialog  劆        劆                  劆                劔
;;    劔              劌劅劅劅劅劏劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劮
;;    劔              劆dialog 偐傜慡偰傪巜掕偟偰専嶕                 劔
;;    劘劒劒劒劒劒劒劒劯劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劗
;;

;; Installation:
;;
;;      1. 傾乕僇僀僽傪揥奐偟偰 ggrep.l 傪 $XYZZY/site-lisp 偵
;;         僐僺乕偟傑偡丅
;;         toolbar-ggrep.bmp 傪 $XYZZY/etc 偵僐僺乕偟傑偡丅
;;
;;      2. 僶僀僩僐儞僷僀儖偟傑偡丅
;;
;;              M-x byte-compile-file
;;              Byte compile file: $XYZZY/site-lisp/ggrep.l
;;
;;      3. ~/.xyzzy 傑偨偼 $XYZZY/site-lisp/siteinit.l 偵埲壓偺僐乕僪傪
;;         捛壛偟傑偡丅
;;
;;              (require "ggrep")
;;
;;      4. 忋婰偺愝掕傪斀塮偝偣傞偨傔偵丄xyzzy 傪嵞婲摦偟傑偡丅
;;         siteinit.l 偵婰弎偟偨応崌偼 Ctrl 僉乕偲 Shift 僉乕傪墴偟側偑傜
;;         xyzzy 傪嵞婲摦偟丄僟儞僾僼傽僀儖傪嵞峔抸偟傑偡丅
;;

;; Uninstallation:
;;
;;      1. ESC ESC (ed::ggrep-uninstall) 偲僞僀僾偟丄
;;         ggrep.l 娭楢偺忣曬傪 xyzzy 偐傜嶍彍偟傑偡丅
;;
;;      2. ggrep.l 偵娭偡傞婰弎傪嶍彍偟傑偡丅
;;
;;      3. siteinit.l 偵婰弎偟偰偄偨応崌偼 Ctrl 僉乕偲 Shift 僉乕傪墴偟
;;         側偑傜 xyzzy 傪嵞婲摦偟丄僟儞僾僼傽僀儖傪嵞峔抸偟傑偡丅
;;

;; Usage:
;;
;;      A: 僶僢僼傽慡懱傪惓婯昞尰偱専嶕
;;        1. M-x ggrep
;;
;;      B: 僶僢僼傽慡懱傪暥帤楍偱専嶕
;;        1. M-x fggrep
;;
;;      C: 尰嵼偺僶僢僼傽偩偗傪専嶕
;;        1. C-u M-x ggrep
;;
;;      D: 巜掕僨傿儗僋僩儕埲壓偺僼傽僀儖傪専嶕
;;        1. M-x xggrep
;;
;;      E: 巜掕僼傽僀儖傪専嶕
;;        1. M-x zggrep
;;
;;      F: 峣崬傒専嶕 1
;;        1. A乣E 偱専嶕
;;        2. A乣E 偺専嶕偵専嶕忦審傪捛壛偟偰丄怴偨偵専嶕
;;
;;      G: 峣崬傒専嶕 2
;;        1. A乣E 偱専嶕
;;        2. 1. 偺寢壥傪尦偵 M-x ggrep-narrow 偱峣崬傒専嶕
;;
;;      H: 峣崬傒専嶕 3
;;        1. M-x ggrep-contents 偱僶僢僼傽傪専嶕
;;        2. 1. 偺寢壥僶僢僼傽忋偱嵞搙 M-x ggrep-contents 偱専嶕
;;
;;      I: 僶僢僼傽偵崌傢偣偨曽朄偱専嶕
;;        1. M-x ggrep-buffer 偱専嶕
;;           - 捠忢僶僢僼傽忋側傜偽 C-u M-x ggrep 偲摨條偺曽朄偱専嶕
;;           - ggrep-contents 寢壥僶僢僼傽忋側傜偽丄嵞搙
;;             M-x ggrep-contents 偲摨條偺曽朄偱専嶕
;;           - 偦偺懠 ggrep 寢壥僶僢僼傽忋側傜偽丄M-x ggrep-narrow 偲
;;             摨條偺曽朄偱専嶕
;;        2. 1. 偺寢壥僶僢僼傽忋偱嵞搙 M-x ggrep-buffer 偱専嶕
;;
;;      J: minibuffer 偐傜嵶偐偔巜掕偟偰専嶕
;;        1. M-x ggrep-detail
;;
;;      K: 僟僀傾儘僌偐傜専嶕
;;        a. 僟僀傾儘僌偺昞帵
;;          - [専嶕]-[GGrep] 傪慖戰
;;          - [昞帵]-[僣乕儖僶乕]-[GGrep] 偱僣乕儖僶乕傪昞帵偟偨忋偱丄
;;             ggrep 僣乕儖僶乕(儃僞儞) 傪慖戰
;;          - M-x ggrep-dialog 傪幚峴
;;
;;        b. 専嶕幚峴
;;          1. 専嶕曽朄傪僟僀傾儘僌偱愝掕偡傞
;;          2. 乽専嶕乿儃僞儞傪墴偡
;;
;;        c. 専嶕愝掕偺曐懚
;;          1. 乽愝掕乿僼傿乕儖僪偵愝掕柤傪擖椡偡傞
;;          2. 乽曐懚乿儃僞儞傪墴偡
;;
;;        d. 専嶕愝掕偺撉崬
;;          1. 乽愝掕乿僼傿乕儖僪偱愝掕柤傪慖戰/擖椡偡傞
;;          2. 乽撉崬乿儃僞儞傪墴偡
;;
;;        e. 専嶕愝掕偺嶍彍
;;          1. 乽愝掕乿僼傿乕儖僪偱愝掕柤傪慖戰/擖椡偡傞
;;          2. 乽嶍彍乿儃僞儞傪墴偡
;;

;; Customize:
;;
;;      専嶕曽朄巜掕
;;          *ggrep-narrow-method*    (nil | :and | :or)
;;          *fggrep-narrow-method*   (nil | :and | :or)
;;          *xggrep-method*          (nil | :and | :or)
;;          *zggrep-method*          (nil | :and | :or)
;;          *ggrep-buffer-method*    (nil | :and | :or)
;;          *ggrep-contents-method*  (nil | :and | :or)
;;
;;      僼僢僋
;;          *ggrep-hook*
;;          *ggrepd-hook*
;;
;;      嫮挷昞帵
;;          *ggrep-highlight-match*
;;
;;      儊僯儏乕偺捛壛埵抲:
;;          (ggrep-insert-menu-items
;;           :menu     儊僯儏乕                   (<menu>)
;;           :pre-tag  捛壛埵抲捈慜儊僯儏乕偺僞僌 (<symbol>)
;;           :position 埵抲(:pre-tag 偑桪愭)      (<symbol> | <integer>)
;;           :head-sep 慜嬫愗傝慄                 (nil | <non-nil>)
;;           :tail-sep 屻嬫愗傝慄                 (nil | <non-nil>)
;;           )
;;

;; Changes:
;;
;;      Sat, 08 Oct 2005 12:17:35 +0900
;;        丒儊乕儖傾僪儗僗傪曄峏丅
;;        丒儔僀僙儞僗忦崁(廋惓BSD儔僀僙儞僗)傪婰嵹丅
;;
;;      Sun, 17 Apr 2005 03:48:55 +0900
;;        丒xyzzy 0.2.2.234 懳墳
;;          - "俵俽 俹僑僔僢僋" 佀 "MS UI Gothic"
;;          - 敿妏僇僫傪慡妏僇僫偵曄峏丅
;;            佀乽僨傿儗僋僩儕乿乽専嶕僶僢僼傽乿乽峣崬傒僶僢僼傽乿偵
;;              <...> (... 偼敿妏僇僫) 傪巜掕偟偰偄偨応崌偼丄懳墳偡傞慡
;;              妏僇僫偺崁栚傪慖傃捈偡昁梫偑偁傞丅
;;          - ggrep-insert-menu-items 峏怴丅
;;            乽GGrep乿儊僯儏乕傪捛壛偡傞埵抲偺僨僼僅儖僩傪乽Grep乿
;;             偺壓偵丅
;;        丒僐儊儞僩廋惓丅
;;
;;      Tue, 14 Dec 2004 19:05:43 +0900
;;        丒ggrep-scan-buffer 偺専嶕岠棪傪 syntax 巜掕帪懡彮埨掕偟偰専嶕
;;          偱偒傞傛偆偵丅
;;
;;      Mon, 13 Dec 2004 00:06:14 +0900
;;        丒ggrep-dialog 偺乽峣崬傒乿偱 <僇儗儞僩僶僢僼傽> 傪慖戰偱偒傞傛
;;          偆偵丅
;;        丒ggrep-dialog 偺乽愝掕乿柤偑擖椡偝傟偰偄側偄忬懺偱乽曐懚乿傪
;;          偟偨応崌丄偦偺帪揰偺擔帪偐傜愝掕柤傪寛掕偡傞傛偆偵奼挘丅
;;        丒ggrep-detail 偱偺乽峣崬傒(narrow)乿専嶕偑摦嶌偟側偄僶僌傪廋惓丅
;;
;;      Wed, 08 Dec 2004 00:27:20 +0900
;;        丒ggrep-scanner 僐儊儞僩捛壛丅僐乕僪曄峏丅
;;        丒僶僢僼傽専嶕偺応崌偼丄儅僢僠奐巒埵抲偺 syntax 傪巜掕偱偒傞傛偆
;;          偵奼挘丅
;;          - ggrep-scan-buffer 捛壛丅
;;          - ggrep-dialog, ggrep1, ggrep-scanner 奼挘丅
;;          - ggrep-internal, ggrep-detail 奼挘丅
;;        丒撪晹巊梡娭悢 ggrep-buffer-list 傪 ggrep-narrow-buffer-list 偵
;;          柤徧曄峏丅
;;        丒ggrep-dialog 偺[僼傽僀儖/僶僢僼傽/峣崬傒]傪巜掕偡傞擖椡僼傿乕
;;          儖僪傪偦傟偧傟撈棫偵丅
;;        丒僐儊儞僩 typo 廋惓丅
;;        丒偦偺懠丅
;;
;;      Wed, 28 Jul 2004 00:31:38 +0900
;;        丒method 傪 ed::and ed::or 偐傜 :and :or 偵曄峏丅
;;        丒ggrep, fggrep 偱巜掕偡傞 method 傪暥帤楍偐傜 :and, :or 偵曄峏丅
;;        丒*last-ggrep-method* 偺帩偮抣傪 method 傪敾暿偡傞暥帤楍
;;          ("and", "or") 偐傜 method 僔儞儃儖 (:and, :or) 偵曄峏丅
;;        丒僨傿儗僋僩儕巜掕 xggrep丄僼傽僀儖巜掕 zggrep 捛壛丅
;;        丒ggrep1 偺嵟屻偺 hook 傪 *ggrep-hook* 屌掕偵曄峏丅
;;        丒ggrep-dialog 偵乽僋儕傾乿儃僞儞捛壛丅
;;        丒乽僐儞僥儞僣偺傒弌椡乿僆僾僔儑儞傪捛壛丅
;;        丒" " 偐傜巒傑傞僶僢僼傽柤偺僶僢僼傽偱傕丄柧帵揑偵巜掕偝傟偨応崌偼
;;          専嶕懳徾偲偡傞傛偆偵曄峏丅(grep 偲偼堎側傞)
;;        丒堦峴堦儗僐乕僪偺 DB 傪専嶕偡傞梡搑偵梡偄傞偙偲傪憐掕偟偨
;;          ggrep-contents 傪捛壛丅捛壛偵偁偨傝丄ggrep1 廋惓丅
;;        丒懳徾僶僢僼傽偵傛傝 ggrep, ggrep-narrow, ggrep-contents 傪
;;          愗傝懼偊傞 ggrep-buffer 傪捛壛丅
;;
;;      Tue, 27 Jul 2004 00:11:01 +0900
;;        丒ggrep-dialog 偱奺庬憖嶌帪偵乽愝掕乿柤傪堷偒宲偖傛偆偵丅
;;          堷偒宲偖偩偗偱愝掕曐懚偼乽曐懚乿傪墴壓帪丅
;;
;;      Sun, 11 Jul 2004 23:33:45 +0900
;;        丒峴扨埵峣崬傒専嶕捛壛丅
;;        丒ggrep-narrow, fggrep-narrow 捛壛丅
;;
;;      Fri, 21 May 2004 14:25:22 +0900
;;        丒僼傽僀儖儕僗僩(僼儖僷僗)巜掕専嶕捛壛丅
;;        丒僶僢僼傽儕僗僩(惓婯昞尰)巜掕専嶕捛壛丅
;;
;;      Tue, 18 May 2004 01:41:10 +0900
;;        丒峣崬傒専嶕懳徾僶僢僼傽偑側偄応崌偼慖戰僐儞儃儃僢僋僗傪
;;          柍岠偵丅
;;
;;      Mon, 17 May 2004 00:26:01 +0900
;;        丒AND 専嶕偑 2004/2/17 埲崀摦嶌偟偰偄側偐偭偨偺傪廋惓丅
;;        丒峣崬傒専嶕捛壛丅
;;        丒ggrep-scan-files-async 偺 typo 廋惓丅
;;
;;      Wed, 03 Mar 2004 22:47:44 +0900
;;        丒僣乕儖僶乕捛壛丅
;;
;;      Tue, 17 Feb 2004 23:13:52 +0900
;;        丒ggrep-find-error-scanner 偺捛壛丅
;;        丒OR 専嶕側偳偺惈擻傪懡彮夵慞丅(scanner 巇條偺奼挘)
;;        丒偦偺懠丅
;;
;;      Thu, 12 Feb 2004 19:00:36 +0900
;;        丒encoding 傪巜掕偟偰偺専嶕傪壜擻偵丅
;;          僶僢僼傽偵撉傒崬傒嵪傒偺応崌偼丄巜掕 encoding 偼堄幆偟側偄丅
;;
;;      Sat, 04 Oct 2003 01:23:47 +0900
;;        丒*ggrep-patterns*, *ggrep-directories* 偺弶婜抣傪廋惓丅
;;
;;      Mon, 04 Aug 2003 12:56:05 +0900
;;        丒懚嵼偟側偄愝掕柤偱乽撉崬乿偟偨嵺丄愝掕傪僋儕傾偡傞傛偆偵曄峏丅
;;
;;      Mon, 28 Jul 2003 08:25:31 +0900
;;        丒ggrep-dirs-normalization 廋惓丅
;;
;;      Mon, 28 Jul 2003 00:33:01 +0900
;;        丒弶斉嶌惉丅
;;

;; Restriction:
;;
;;      丒峣崬傒専嶕懳徾巜掕僶僢僼傽偵丄僶僢僼傽/僼傽僀儖偺専嶕寢壥偑
;;        崿嵼偟偰偄傞応崌偺摦嶌偼晄掕丅
;;
;;      丒専嶕懳徾偲偟偰僶僢僼傽/僼傽僀儖傪崿嵼偝偣偨応崌偺摦嶌偼晄掕丅
;;
;;      丒専嶕懳徾偑僶僢僼傽偺応崌旕摨婜専嶕晄壜丅
;;
;;      丒専嶕寢壥偲偟偰丄僶僢僼傽/僼傽僀儖柤偺傒弌椡偡傞応崌偼丄
;;        峴扨埵峣崬傒専嶕晄壜丅奺僶僢僼傽/僼傽僀儖慡懱偐傜専嶕偡傞丅
;;
;;      丒戝検偺僼傽僀儖偵懳偟偰偺摨婜専嶕偱屌傑傞偙偲偑偁傞
;;        僶僀僩僐儞僷僀儖偡傞偲敪惗偟側偔側偭偨偑崻杮尨場枹挷嵏丅
;;

;; Todo:
;;      丒AND, OR 偩偗偱側偔丄COMPLEX 専嶕偺捛壛丅
;;        ex?) (and "abc" "def" (or "ghi" (not "jkl")))
;;
;;      丒僄儞僐乕僪巜掕専嶕偺寢壥偐傜偺 first-error, next-error 帪
;;        偵偼丄巜掕僄儞僐乕僪偱僼傽僀儖傪奐偒側偍偡丅
;;
;;      丒first-error, next-error 帪偺嫮挷昞帵偺廋惓丅
;;        尰嵼偼丄娙堈揑偵懳徾峴堦峴慡偰傪嫮挷昞帵丅
;;
;;      丒旕摨婜 ggrep 帪偺幚峴奐巒帪偺懸偪偺夝徚丅
;;
;;      丒僟僀傾儘僌偱偺 <僇儗儞僩僨傿儗僋僩儕> 昞帵傪
;;        <僨僼僅儖僩僨傿儗僋僩儕> 偵曄峏偡傞偐専摙丅
;;        <僶僢僼傽僨傿儗僋僩儕> 偺曽偑暘偐傝傗偡偄偐丠
;;

;; Memo:
;;  丒grep 偱偼 " " 偐傜巒傑傞僶僢僼傽柤偺僶僢僼傽傪柧帵揑偵巜掕偟偰傕
;;    専嶕傪峴傢側偄偑 ggrep 偱偼柧帵揑偵巜掕偝傟偨応崌偼専嶕偡傞傛偆偵
;;    曄峏偟偨丅
;;
;;  丒hook 梡 symbol 柤 *ggrep-hook*, *ggrepd-hook* 偐傜偼丄ggrep-dialog
;;    幚峴屻偼 *ggrepd-hook* 偑丄偦傟埲奜偺応崌偼 *ggrep-hook* 偑張棟偝傟傞
;;    傛偆偵巚偊傞偑丄偦偆偱偼側偄丅
;;    廬棃偼丄minibuffer 偐傜偺 grep 偱偼専嶕懳徾偑僶僢僼傽偺傒丄grep-dialog
;;    偐傜偺専嶕偱偼専嶕懳徾偑僼傽僀儖偺傒偱偁偭偨偨傔丄僶僢僼傽専嶕梡
;;    function 偱偁傞 grep1 偱偼 *grep-hook* 偑丄偦傟埲奜偱偼 *grepd-hook*
;;    偑梡偄傜傟偰偄傞丅
;;    ggrep 娭楢偺 function 偱偼 minibuffer/dialog 偺椉曽偐傜僶僢僼傽/僼傽僀儖
;;    偺専嶕傪峴偆偑丄僼傽僀儖傪専嶕懳徾偵娷傓応崌偵偼 *ggrepd-hook* 傪丄
;;    僼傽僀儖傪専嶕懳徾偵娷傑側偄応崌偵偼 *ggrep-hook* 傪梡偄傞偙偲偲偡傞丅
;;
;;  丒dialog 偱偺愝掕曄峏傪偳偙傑偱 minibuffer 偱偺幚峴帪偵斀塮偝偣傞偐丅
;;    梫専摙丅
;;  丒*find-error-scanner* 偼 goto-error 偱梡偄傜傟傞丅
;;  丒ggrep-scanner 偱曉偡 function 偺堷悢 limit 偼 goto-error
;;    (first-error, next-error) 偱偺傒梡偄傜傞丅
;;    嫮挷昞帵偺偨傔偵梡偄傜傟傞丅
;;
;;  丒屇傃弌偟弴彉
;;
;;  grep-dialog (sync)
;;  劋 editor::grep-dialog-1
;;     劋 editor::scan-files
;;        劌 editor::grep-scanner
;;        劋 editor::scan-files-sync
;;           劌 editor::scan-files-setup
;;           劋 editor::scan-files-1
;;              劋 editor::grep-scan-file
;;                 劋 scan-buffer
;;
;;  grep-dialog (async)
;;  劋 editor::grep-dialog-1
;;     劋 editor::scan-files
;;        劌 editor::grep-scanner
;;        劋 editor::scan-files-async
;;           劌 editor::scan-files-setup
;;           劌 editor::async-grep-mode
;;           劌 editor::grep-async-scanner
;;           劋 start-timer
;;
;;  xgrep
;;  劋 editor::scan-files
;;     劌 editor::grep-scanner
;;     劋 editor::scan-files-sync
;;        劌 editor::scan-files-setup
;;        劋 editor::scan-files-1
;;           劋 editor::grep-scan-file
;;              劋 scan-buffer
;;
;;  ggrep-dialog (sync)
;;  劌 editor::ggrep-load-setting
;;  劌 editor::ggrep-make-setting
;;  劌 editor::ggrep-patterns-normalization
;;  劋 editor::ggrep-scan-files
;;     劌 editor::ggrep-patterns-normalization
;;     劌 editor::ggrep-dirs-normalization
;;     劌 editor::ggrep-scanner
;;     劋 editor::ggrep-scan-files-sync
;;        劌 editor::scan-files-setup
;;        劋 editor::ggrep-scan-files-1
;;           劋 editor::ggrep-scan-file
;;              劋 scan-buffer
;;
;;  ggrep-dialog (async)
;;  劌 editor::ggrep-load-setting
;;  劌 editor::ggrep-make-setting
;;  劌 editor::ggrep-patterns-normalization
;;  劋 editor::ggrep-scan-files
;;     劌 editor::ggrep-patterns-normalization
;;     劌 editor::ggrep-dirs-normalization
;;     劌 editor::ggrep-scanner
;;     劋 editor::ggrep-scan-files-async
;;        劌 editor::scan-files-setup
;;        劌 editor::async-ggrep-mode
;;        劌 editor::ggrep-async-scanner
;;        劋 start-timer
;;

;; Licence:
;;
;;    ggrep 偼廋惓BSD儔僀僙儞僗偵婎偯偄偰棙梡壜擻偱偡丅
;;    <http://www.opensource.org/licenses/bsd-license.php>
;;
;;
;;    Copyright (C) 2001-2005, OHKUBO Hiroshi.  All rights reserved.
;;
;;    Redistribution and use in source and binary forms, with or without
;;    modification, are permitted provided that the following conditions
;;    are met:
;;
;;    1. Redistributions of source code must retain the above copyright
;;       notice, this list of conditions and the following disclaimer.
;;
;;    2. Redistributions in binary form must reproduce the above copyright
;;       notice, this list of conditions and the following disclaimer in
;;       the documentation and/or other materials provided with the
;;       distribution.
;;
;;    3. Neither the name of the University nor the names of its
;;       contributors may be used to endorse or promote products derived
;;       from this software without specific prior written permission.
;;
;;    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;;    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
;;    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
;;    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
;;    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
;;    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
;;    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
;;    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
;;    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;;    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;;    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;;

;;; Code:

(provide "ggrep")

(require "grep")
(require "grepd")
(require "minibuf")
(require "encoding")

(in-package "editor")

(export '(ggrep-dialog ggrep-detail
          ggrep ggrep-and ggrep-or ggrep-narrow
          fggrep fggrep-and fggrep-or fggrep-narrow
          xggrep zggrep ggrep-contents
          ggrep-buffer
          ggrep-insert-menu-items
          ggrep-delete-menu
          *ggrep-narrow-method*
          *fggrep-narrow-method*
          *xggrep-method*
          *zggrep-method*
          *ggrep-contents-method*
          *ggrep-buffer-method*
          *ggrep-hook*
          *ggrepd-hook*))

(defvar *ggrep-narrow-method* nil)
(defvar *fggrep-narrow-method* nil)
(defvar *xggrep-method* nil)
(defvar *zggrep-method* nil)
(defvar *ggrep-buffer-method* nil)
(defvar *ggrep-contents-method* nil)

(defvar *ggrep-highlight-match* *grep-highlight-match*)
(defvar *ggrep-hook* nil)
(defvar *ggrepd-hook* nil)

(defvar *ggrep-method* nil)
(defvar *ggrep-patterns* nil)
(defvar *ggrep-select-target-method* nil "'buffer-list, 'file-list, nil")
(defvar *ggrep-target-type* nil ":file, :buffer, :narrow")
(defvar *ggrep-directories* nil)
(defvar *ggrep-file* "*")
(defvar *ggrep-buffer* "<僇儗儞僩僶僢僼傽>")
(defvar *ggrep-narrow-buffer* nil)
(defvar *ggrep-narrow-unit* nil
  "峣崬傒専嶕扨埵偺巜掕
:buffer : 僶僢僼傽/僼傽僀儖峣崬傒
:line   : 峴峣崬傒
忋婰埲奜: 峴峣崬傒")
(defvar *ggrep-file-list* nil)
(defvar *ggrep-buffer-regexp-list* nil)
(defvar *ggrep-encoding-name* nil)
(defvar *ggrep-encoding-check-file* nil)
(defvar *ggrep-syntax* t)
(defvar *ggrep-case-fold-search* *grep-case-fold-search*)
(defvar *ggrep-word-search* *grep-word-search*)
(defvar *ggrep-regexp-search* *grep-regexp-search*)
(defvar *ggrep-understand-escape-sequences* *grep-understand-escape-sequences*)
(defvar *ggrep-async* *grep-async*)
(defvar *ggrep-contents-only* nil)
(defvar *ggrep-name-only* *grep-name-only*)
(defvar *ggrep-full-name* nil)

(defvar *ggrep-subdir-default* nil)
(defconstant *ggrep-dialog-number-of-pattern-min* 1)
(defconstant *ggrep-dialog-number-of-dir-min* 1)
(defvar *ggrep-dialog-number-of-pattern* 3)
(defvar *ggrep-dialog-number-of-dir* 3)

(defvar *ggrep-method-alist* '(("AND" . :and) ("OR" . :or)))

(defvar *ggrep-contents-only-bufname* "*match contents*")

(define-history-variable *last-ggrep-regexp-list* nil)
(define-history-variable *last-fggrep-pattern-list* nil)
(define-history-variable *last-ggrep-method* nil)
(define-history-variable *last-ggrep-setting* nil)
(define-history-variable *ggrep-setting-history* nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ggrep (method regexp-list &optional arg)
  (interactive
      (let (method patterns)
        (multiple-value-setq (patterns method)
          (ggrep-read-patterns :command-name "ggrep"
                               :regexp-search t
                               :nomatch-search-use nil))
        (list method patterns (eq *last-command* 'universal-argument))))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-ggrep-regexp-list* regexp-list))
  (ggrep-internal :buffer-list arg
                  ;; 専嶕僷僞乕儞
                  :method method
                  :patterns regexp-list
                  :regexp-search t
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun ggrep-and (regexp-list &optional arg)
  (interactive
      (let (patterns)
        (setq patterns (ggrep-read-patterns :command-name "ggrep-and"
                                            :regexp-search t
                                            :method :and
                                            :nomatch-search-use nil))
        (list patterns (eq *last-command* 'universal-argument))))
  (when (interactive-p)
    (setq *last-ggrep-regexp-list* regexp-list))
  (ggrep-internal :buffer-list arg
                  ;; 専嶕僷僞乕儞
                  :method :and
                  :patterns regexp-list
                  :regexp-search t
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun ggrep-or (regexp-list &optional arg)
  (interactive
      (let (patterns)
        (setq patterns (ggrep-read-patterns :command-name "ggrep-or"
                                            :regexp-search t
                                            :method :or
                                            :nomatch-search-use nil))
        (list patterns (eq *last-command* 'universal-argument))))
  (when (interactive-p)
    (setq *last-ggrep-regexp-list* regexp-list))
  (ggrep-internal :buffer-list arg
                  ;; 専嶕僷僞乕儞
                  :method :or
                  :patterns regexp-list
                  :regexp-search t
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun ggrep-narrow (method regexp-list &optional buffer)
  (interactive
      (let (method patterns buffer args)
        (when (eq *last-command* 'universal-argument)
          (setq buffer (ggrep-read-narrow :command-name "ggrep-narrow"
                                          :narrow-unit :line)))
        (setq args (list :command-name "ggrep-narrow"
                         :regexp-search t
                         :nomatch-search-use nil))
        (when *ggrep-narrow-method*
          (setq args (nconc args (list :method *ggrep-narrow-method*))))
        (multiple-value-setq (patterns method)
          (apply 'ggrep-read-patterns args))
        (list method patterns buffer)))
  (unless buffer
    (setq buffer (selected-buffer)))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-ggrep-regexp-list* regexp-list))
  (ggrep-internal :narrow-buffer buffer
                  :narrow-unit :line
                  ;; 専嶕僷僞乕儞
                  :method method
                  :patterns regexp-list
                  :regexp-search t
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun fggrep (method pattern-list &optional arg)
  (interactive
      (let (method patterns)
        (multiple-value-setq (patterns method)
          (ggrep-read-patterns :command-name "fggrep"
                               :regexp-search nil
                               :nomatch-search-use nil))
        (list method patterns (eq *last-command* 'universal-argument))))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-fggrep-pattern-list* pattern-list))
  (ggrep-internal :buffer-list arg
                  ;; 専嶕僷僞乕儞
                  :method method
                  :patterns pattern-list
                  :regexp-search nil
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun fggrep-and (pattern-list &optional arg)
  (interactive
      (let (patterns)
        (setq patterns (ggrep-read-patterns :command-name "fggrep-and"
                                            :regexp-search nil
                                            :method :and
                                            :nomatch-search-use nil))
        (list patterns (eq *last-command* 'universal-argument))))
  (when (interactive-p)
    (setq *last-fggrep-pattern-list* pattern-list))
  (ggrep-internal :buffer-list arg
                  ;; 専嶕僷僞乕儞
                  :method :and
                  :patterns pattern-list
                  :regexp-search nil
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun fggrep-or (pattern-list &optional arg)
  (interactive
      (let (patterns)
        (setq patterns (ggrep-read-patterns :command-name "fggrep-or"
                                            :regexp-search nil
                                            :method :or
                                            :nomatch-search-use nil))
        (list patterns (eq *last-command* 'universal-argument))))
  (when (interactive-p)
    (setq *last-fggrep-pattern-list* pattern-list))
  (ggrep-internal :buffer-list arg
                  ;; 専嶕僷僞乕儞
                  :method :or
                  :patterns pattern-list
                  :regexp-search nil
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun fggrep-narrow (method pattern-list &optional buffer)
  (interactive
      (let (method patterns buffer args)
        (when (eq *last-command* 'universal-argument)
          (setq buffer (ggrep-read-narrow :command-name "fggrep-narrow"
                                          :narrow-unit :line)))
        (setq args (list :command-name "fggrep-narrow"
                         :regexp-search nil
                         :nomatch-search-use nil))
        (when *fggrep-narrow-method*
          (setq args (nconc args (list :method *fggrep-narrow-method*))))
        (multiple-value-setq (patterns method)
          (apply 'ggrep-read-patterns args))
        (list method patterns buffer)))
  (unless buffer
    (setq buffer (selected-buffer)))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-fggrep-pattern-list* pattern-list))
  (ggrep-internal :narrow-buffer buffer
                  :narrow-unit :line
                  ;; 専嶕僷僞乕儞
                  :method method
                  :patterns pattern-list
                  :regexp-search nil
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun xggrep (method regexp-list dirs files)
  (interactive
      (let (method patterns dirs files args)
        (setq args (list :command-name "xggrep"
                         :regexp-search t
                         :nomatch-search-use nil))
        (when *xggrep-method*
          (setq args (nconc args (list :method *xggrep-method*))))
        (multiple-value-setq (patterns method)
          (apply 'ggrep-read-patterns args))
        (multiple-value-setq (dirs files)
          (ggrep-read-dirs :command-name "xggrep"
                           :subdir-constant t))
        (list method patterns dirs files)))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-ggrep-regexp-list* regexp-list))
  (ggrep-internal :dirs dirs
                  :files files
                  ;; 専嶕僷僞乕儞
                  :method method
                  :patterns regexp-list
                  :regexp-search t
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun zggrep (method regexp-list file-list)
  (interactive
      (let (method patterns file-list args)
        (setq args (list :command-name "zggrep"
                         :regexp-search t
                         :nomatch-search-use nil))
        (when *zggrep-method*
          (setq args (nconc args (list :method *zggrep-method*))))
        (multiple-value-setq (patterns method)
          (apply 'ggrep-read-patterns args))
        (setq file-list (ggrep-read-file-list :command-name "zggrep"))
        (list method patterns file-list)))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-ggrep-regexp-list* regexp-list))
  (ggrep-internal :file-list file-list
                  ;; 専嶕僷僞乕儞
                  :method method
                  :patterns regexp-list
                  :regexp-search t
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only nil
                  :name-only nil
                  :full-name *ggrep-full-name*))

(defun ggrep-contents (method regexp-list &optional buffer)
  (interactive
      (let (method patterns buffer buffer-name-list args)
        (when (eq *last-command* 'universal-argument)
          (dolist (buffer (buffer-list))
            (unless (string-match "^ " (buffer-name buffer))
              (push (buffer-name buffer) buffer-name-list)))
          (setq buffer
                (find-buffer
                 (completing-read "ggrep-contents buffer: "
                                  buffer-name-list
                                  :default (buffer-name (selected-buffer))
                                  :must-match t))))
        (setq args (list :command-name "ggrep-contents"
                         :regexp-search t
                         :nomatch-search-use nil))
        (when *ggrep-contents-method*
          (setq args (nconc args (list :method *ggrep-contents-method*))))
        (multiple-value-setq (patterns method)
          (apply 'ggrep-read-patterns args))
        (list method patterns buffer)))
  (unless buffer
    (setq buffer (selected-buffer)))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-ggrep-regexp-list* regexp-list))
  (ggrep-internal :buffer-list (if (listp buffer) buffer (list buffer))
                  ;; 専嶕僷僞乕儞
                  :method method
                  :patterns regexp-list
                  :regexp-search t
                  :encoding-name nil
                  :syntax t
                  :case-fold *ggrep-case-fold-search*
                  :word-search *ggrep-word-search*
                  :async *ggrep-async*
                  :contents-only t))

(defun ggrep-buffer (method regexp-list &optional buffer)
  (interactive
      (let (method patterns buffer buffer-name-list args)
        (if (eq *last-command* 'universal-argument)
            (progn
              (dolist (buffer (buffer-list))
                (unless (string-match "^ " (buffer-name buffer))
                  (push (buffer-name buffer) buffer-name-list)))
              (setq buffer
                    (find-buffer
                     (completing-read "ggrep-buffer buffer: "
                                      buffer-name-list
                                      :default (buffer-name (selected-buffer))
                                      :must-match t))))
          (setq buffer (selected-buffer)))
        (setq args (list :command-name "ggrep-buffer"
                         :regexp-search t
                         :nomatch-search-use nil))
        (when *ggrep-buffer-method*
          (setq args (nconc args (list :method *ggrep-buffer-method*))))
        (multiple-value-setq (patterns method)
          (apply 'ggrep-read-patterns args))
        (list method patterns buffer)))
  (unless buffer
    (setq buffer (selected-buffer)))
  (when (interactive-p)
    (setq *last-ggrep-method* method)
    (setq *last-ggrep-regexp-list* regexp-list))
  (cond
   ((string= (buffer-name buffer) *ggrep-contents-only-bufname*)
    (ggrep-contents method regexp-list buffer))
   ((member buffer (ggrep-narrow-buffer-list))
    (ggrep-narrow method regexp-list buffer))
   (t
    (ggrep method regexp-list (list buffer)))))

(defun ggrep-detail (&key
                     ;; ---------- 専嶕僷僞乕儞 ----------
                     (method nil method-sv)
                     (patterns nil patterns-sv)
                     (regexp-search *ggrep-regexp-search* regexp-search-sv)
                     ;; ---------- 専嶕懳徾 ----------
                     ; 1. 擟堄偺専嶕懳徾巜掕偑壜擻
                     (target-list nil target-list-sv)
                     ; 2. 峣崬傒懳徾僶僢僼傽 & 峣崬傒扨埵
                     (narrow-buffer nil narrow-buffer-sv)
                     (narrow-unit nil narrow-unit-sv)
                     ; 3. 僶僢僼傽捈愙巜掕 (t, nil, buffer-list)
                     (buffer-list nil buffer-list-sv)
                     ; 4. 僶僢僼傽惓婯昞尰巜掕
                     (buffer-regexp-list nil buffer-regexp-list-sv)
                     ; 5. 僼傽僀儖捈愙巜掕
                     (file-list nil file-list-sv)
                     ; 6. 僨傿儗僋僩儕柤 & 僼傽僀儖柤僷僞乕儞
                     (dirs nil dirs-sv)
                     (files nil files-sv)
                     ;; ----------
                     (encoding-name nil encoding-name-sv)
                     (encoding-check-file nil encoding-check-file-sv)
                     (syntax t syntax-sv)
                     (case-fold *ggrep-case-fold-search* case-fold-sv)
                     (word-search *ggrep-word-search* word-search-sv)
                     (async *ggrep-async* async-sv)
                     (contents-only *ggrep-contents-only* contents-only-sv)
                     (name-only *ggrep-name-only* name-only-sv)
                     (full-name *ggrep-full-name* full-name-sv))
  (interactive
      (let ((command-name "ggrep-detail ")
            target-type args buffer-list buffer-regexp-list
            dirs files file-list
            narrow-buffer narrow-unit
            patterns method regexp-search
            target-list buffer-only-p
            return-args)
        ;; ------------------------------------------------------------
        ;; 専嶕懳徾巜掕
        (setq target-type
              (completing-read
               (format nil "~Atarget-type (buffer/all-buffers/buffer-regexp/dir/file/narrow): "
                       command-name)
               '("buffer" "all-buffers" "buffer-regexp" "dir" "file" "narrow")
               :case-fold t
               :must-match t))

        ;; ------------------------------------------------------------
        ;; 専嶕懳徾枅暘婒張棟
        (cond
         ;; 暋悢僶僢僼傽巜掕 -> buffer-list
         ((string= target-type "buffer")
          (setq args (list :command-name command-name))
          (setq buffer-list (apply 'ggrep-read-buffer-list args))
          (setq return-args (nconc return-args (list :buffer-list buffer-list))))
         ;; 慡僶僢僼傽巜掕 -> buffer-list
         ((string= target-type "all-buffers")
          (setq buffer-list nil)
          (setq return-args (nconc return-args (list :buffer-list buffer-list))))
         ;; 僶僢僼傽惓婯昞尰巜掕 -> buffer-list
         ((string-equal target-type "buffer-regexp")
          (setq args (list :command-name command-name))
          (multiple-value-setq (buffer-regexp-list buffer-list)
            (apply 'ggrep-read-buffer-regexp-list args))
          (setq return-args
                (nconc return-args (list :buffer-regexp-list buffer-regexp-list))))
         ;; 僨傿儗僋僩儕巜掕 -> dirs, files
         ((string-equal target-type "dir")
          (setq args (list :command-name command-name))
          (multiple-value-setq (dirs files)
            (apply 'ggrep-read-dirs args))
          (setq return-args
                (nconc return-args (list :dirs dirs :files files))))
         ;; 暋悢僼傽僀儖巜掕 -> file-list
         ((string-equal target-type "file")
          (setq args (list :command-name command-name))
          (setq file-list (apply 'ggrep-read-file-list args))
          (setq return-args
                (nconc return-args (list :file-list file-list))))
         ;; 峣崬傒専嶕 -> target-list
         ((string-equal target-type "narrow")
          (setq args (list :command-name command-name))
          (multiple-value-setq (narrow-buffer narrow-unit)
            (apply 'ggrep-read-narrow args))
          (setq target-list
                (ggrep-get-target-list narrow-buffer narrow-unit))
          (setq return-args
                (nconc return-args (list :narrow-buffer narrow-buffer
                                         :narrow-unit narrow-unit)))))

        ;; ------------------------------------------------------------
        ;; 専嶕懳徾偑 buffer 偺傒偱偁傞偐斲偐僠僃僢僋
        (cond
         ((member target-type '("narrow") :test #'string=)
          (unless (find-if-not #'(lambda (x)
                                   (or (bufferp x)
                                       (and (stringp x) (find-buffer x))))
                               target-list
                               :key #'(lambda (target)
                                        (if (listp target) (car target) target)))
            (setq buffer-only-p t)))
         ((member target-type '("buffer" "all-buffers" "buffer-regexp") :test #'string=)
          (setq buffer-only-p t)))

        ;; ------------------------------------------------------------
        ;; method, pattern 巜掕
        (setq args (list :command-name command-name))
        (multiple-value-setq (patterns method regexp-search)
          (apply 'ggrep-read-patterns args))
        (setq return-args
              (nconc return-args (list :method method
                                       :patterns patterns
                                       :regexp-search regexp-search)))

        ;; ------------------------------------------------------------
        ;; 僆僾僔儑儞巜掕
        ;; encoding-name
        (unless buffer-only-p
          (setq args (list :command-name command-name))
          (multiple-value-setq (encoding-name encoding-check-file)
            (apply 'ggrep-read-encoding-name args))
          (setq return-args
                (nconc return-args (list :encoding-name encoding-name
                                         :encoding-check-file encoding-check-file))))

        ;; syntax
        (when buffer-only-p
          (setq args (list :command-name command-name))
          (setq syntax (apply 'ggrep-read-syntax args))
          (setq return-args
                (nconc return-args (list :syntax syntax))))

        ;; case-fold, word-search, async, contents-only, name-only, full-name
        (setq args (list :command-name command-name
                         :regexp-search regexp-search
                         :buffer-only-p buffer-only-p))
        (multiple-value-setq (case-fold word-search async contents-only name-only full-name)
          (apply 'ggrep-read-others args))
        (setq return-args (nconc return-args (list :case-fold case-fold)))
        (unless regexp-search
          (setq return-args (nconc return-args (list :word-search word-search))))
        (unless buffer-only-p
          (setq return-args (nconc return-args (list :async async))))
        (setq return-args (nconc return-args (list :contents-only contents-only)))
        (unless contents-only
          (setq return-args (nconc return-args (list :name-only name-only
                                                     :full-name full-name))))
        return-args))
  (let (args)
    (when (interactive-p)
      (setq *last-ggrep-method* method)
      (if regexp-search
          (setq *last-ggrep-regexp-list* patterns)
        (setq *last-fggrep-pattern-list* patterns)))
    (when method-sv
      (setq args (nconc args (list :method method))))
    (when patterns-sv
      (setq args (nconc args (list :patterns patterns))))
    (when regexp-search-sv
      (setq args (nconc args (list :regexp-search regexp-search))))
    (when target-list-sv
      (setq args (nconc args (list :target-list target-list))))
    (when narrow-buffer-sv
      (setq args (nconc args (list :narrow-buffer narrow-buffer))))
    (when narrow-unit-sv
      (setq args (nconc args (list :narrow-unit narrow-unit))))
    (when buffer-list-sv
      (setq args (nconc args (list :buffer-list buffer-list))))
    (when buffer-regexp-list-sv
      (setq args (nconc args (list :buffer-regexp-list buffer-regexp-list))))
    (when file-list-sv
      (setq args (nconc args (list :file-list file-list))))
    (when dirs-sv
      (setq args (nconc args (list :dirs dirs))))
    (when files-sv
      (setq args (nconc args (list :files files))))

    ;; ----------
    (when encoding-name-sv
      (setq args (nconc args (list :encoding-name encoding-name))))
    (when encoding-check-file-sv
      (setq args (nconc args (list :encoding-check-file encoding-check-file))))
    (when syntax-sv
      (setq args (nconc args (list :syntax syntax))))
    (when case-fold-sv
      (setq args (nconc args (list :case-fold case-fold))))
    (when word-search-sv
      (setq args (nconc args (list :word-search word-search))))
    (when async-sv
      (setq args (nconc args (list :async async))))
    (when contents-only-sv
      (setq args (nconc args (list :contents-only contents-only))))
    (when name-only-sv
      (setq args (nconc args (list :name-only name-only))))
    (when full-name-sv
      (setq args (nconc args (list :full-name full-name))))

    (apply 'ggrep-internal args)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ggrep-scan-file (file scanner common-path &optional linenum-list)
  (setq file (subseq file (length common-path)))
  (let ((found nil) (linenum-list (or (sort (copy-list linenum-list) #'<) t))
        current-found)
    ;; scanner 偺弶婜壔 (ggrep 偺 scanner 撈帺)
    (funcall scanner nil t)
    (loop
      (setq current-found nil)
      (unless (eq linenum-list t)
        (if linenum-list
            (goto-line (car linenum-list))
          (return-from ggrep-scan-file found)))
      (multiple-value-bind (one-time-found match-position-list)
          (funcall scanner nil nil)
        (if one-time-found
            (when (or (eq linenum-list t)
                      (member (current-line-number) linenum-list :test #'=))
              (setq current-found t)
              (setq found t))
          (return-from ggrep-scan-file found))
        (unless (eq linenum-list t)
          (setq linenum-list (member (current-line-number) linenum-list :test #'<)))
        (when current-found
          (let ((beg (progn (goto-bol) (point)))
                (end (progn (goto-eol) (point))))
            (if *ggrep-contents-only*
                (format t "~A~%" (buffer-substring beg end))
              (format t "~A:~D:~A~%" file (current-line-number) (buffer-substring beg end)))
            (when (and *ggrep-highlight-match*
                       (buffer-stream-p *standard-output*))
              (save-excursion
                (set-buffer (buffer-stream-buffer *standard-output*))
                (let ((p (- (buffer-stream-point *standard-output*) end 1)))
                  (dolist (match-position match-position-list)
                    (apply #'set-text-attribute
                           (+ (car match-position) p) (+ (cdr match-position) p)
                           'ggrep *ggrep-highlight-match*)))))))
        (or (progn (goto-eol) (forward-char 1))
            (return))))
    found))

(defun ggrep-scan-files-1 (file patterns buffer scanner common-path &optional linenum-list)
  (let ((file-buffer (get-file-buffer file)))
    (if (and file-buffer (not *ggrep-encoding-check-file*))
        (set-buffer file-buffer)
      (let* ((encoding
              (if (or (not *ggrep-encoding-name*)
                      (not (stringp *ggrep-encoding-name*)))
                  *expected-fileio-encoding*
                (car (member *ggrep-encoding-name* *char-encoding-list*
                             :key 'char-encoding-name
                             :test 'string=))))
             (*expected-fileio-encoding*
              (or encoding
                  (find-file-auto-encoding file)
                  *expected-fileio-encoding*)))
        (declare (special *expected-fileio-encoding*))
        (set-buffer buffer)
        (erase-buffer buffer)
        (ignore-errors (insert-file-contents file))))
    (save-excursion
      (goto-char (point-min))
      (message "scanning (~A)" (subseq file (length common-path)))
      (cond (*ggrep-name-only* ;; linenum-list 柍帇
             (when (funcall scanner)
               (princ (subseq file (length common-path)))
               (terpri)
               t))
            (t
             (ggrep-scan-file file scanner common-path linenum-list))))))

(defun ggrep-scan-files-sync (patterns buffer temp scanner file dirs target-list)
  (unwind-protect
      (let (files dirlist common-path)
        (setq files
              (mapcar #'(lambda (target)
                          (if (consp target) (car target) target))
                      target-list))
        (if files
            (progn
              (if *ggrep-full-name*
                  (setq common-path "")
                (setq common-path (glob-common-path files))))
          (progn
            (setq dirlist (glob-expand-list
                           (mapcar #'(lambda (d) (ggrep-get-setting-item d "directory"))
                                   dirs)))
            (unless dirlist
              (error "~S~%僨傿儗僋僩儕偑尒偮偐傝傑偣傫" dirs))
            (setq dirlist (mapcar 'append-trail-slash dirlist))
            (dolist (dir (prog1 (nreverse dirlist) (setq dirlist nil)))
              (unless (member dir dirlist :test 'string=)
                (if dirlist
                    (push dir dirlist)
                  (setq dirlist (list dir)))))
            (if *ggrep-full-name*
                (setq common-path "")
              (setq common-path (if (= (length dirlist) 1)
                                    (car dirlist)
                                  (glob-common-path dirlist))))))
        (scan-files-setup common-path buffer temp (ggrep-find-error-scanner))
        (refresh-screen)
        (with-output-to-selected-buffer
          (let ((last-tick (get-internal-real-time))
                (found nil) tick filelist linenum-list target f)
            (if target-list
                ;; 僞乕僎僢僩儕僗僩(僼傽僀儖儕僗僩)巜掕偺応崌
                (dolist (target target-list)
                  (if (consp target)
                      (progn
                        (setq f (car target))
                        (setq linenum-list (cadr target)))
                    (progn
                      (setq f target)
                      (setq linenum-list nil)))
                  (unless (member f filelist :test 'string=)
                    (if filelist
                        (push f filelist)
                      (setq filelist (list f)))
                    (when (ggrep-scan-files-1 f patterns temp scanner common-path linenum-list)
                      (setq found t))
                    (when found
                      (setq tick (get-internal-real-time))
                      (when (> (- tick last-tick) 500)
                        (setq last-tick tick)
                        (set-buffer buffer)
                        (goto-char (buffer-stream-point *standard-output*))
                        (refresh-screen)
                        (setq found nil)))
                    (do-events)))
              ;; 僨傿儗僋僩儕儕僗僩+僼傽僀儖巜掕偺応崌
              (dolist (d dirs)
                (when (ggrep-get-setting-item d "enable")
                  (glob-exec (glob-expand (ggrep-get-setting-item d "directory"))
                             :recursive (ggrep-get-setting-item d "subdir")
                             :file-only t :wild file
                             :absolute t
                             :callback
                             #'(lambda (f)
                                 (unless (member f filelist :test 'string=)
                                   (if filelist
                                       (push f filelist)
                                     (setq filelist (list f)))
                                   (when (ggrep-scan-files-1 f patterns temp scanner common-path)
                                     (setq found t))
                                   (when found
                                     (setq tick (get-internal-real-time))
                                     (when (> (- tick last-tick) 500)
                                       (setq last-tick tick)
                                       (set-buffer buffer)
                                       (goto-char (buffer-stream-point *standard-output*))
                                       (refresh-screen)
                                       (setq found nil)))
                                   (do-events))))))))))
    (delete-buffer temp)
    (set-buffer buffer)
    (goto-char (point-min)))
  (set-buffer-modified-p nil)
  (run-hooks '*ggrepd-hook*)
  (message "done"))

(or (boundp 'async-ggrep-mode)
    (setq-default async-ggrep-mode nil))
(or (boundp 'async-ggrep-status)
    (setq-default async-ggrep-status nil))
(or (boundp 'async-ggrep-timer-callback)
    (setq-default async-ggrep-timer-callback nil))
(pushnew '(async-ggrep-mode . async-ggrep-status)
         *minor-mode-alist* :key #'car)

(defvar *async-ggrep-mode-map* nil)
(unless *async-ggrep-mode-map*
  (setq *async-ggrep-mode-map* (make-sparse-keymap))
  (define-key *async-ggrep-mode-map* #\C-g 'stop-async-ggrep))

(defun async-ggrep-mode ()
  (kill-all-local-variables)
  (setq buffer-mode 'async-ggrep-mode)
  (setq mode-name "GGrep")
  (use-keymap *async-ggrep-mode-map*)
  (make-local-variable 'async-ggrep-timer-callback)
  (setq async-ggrep-timer-callback nil)
  (make-local-variable 'async-ggrep-temp-buffer)
  (setq async-ggrep-temp-buffer nil)
  (make-local-variable 'async-ggrep-last-update)
  (setq async-ggrep-last-update (get-internal-real-time))
  (make-local-variable 'async-ggrep-mode)
  (setq async-ggrep-mode nil)
  (make-local-variable 'async-ggrep-status))

(defun stop-async-ggrep ()
  (interactive)
  (when async-ggrep-timer-callback
    (set-buffer-modified-p nil)
    (setq async-ggrep-status "done")
    (update-mode-line (selected-buffer))
    (stop-timer async-ggrep-timer-callback)
    (setq async-ggrep-timer-callback nil)
    (when async-ggrep-temp-buffer
      (delete-buffer async-ggrep-temp-buffer)
      (setq async-ggrep-temp-buffer nil))
    (run-hooks '*ggrepd-hook*)
    (message "done"))
  t)

(defun ggrep-async-scanner (patterns buffer temp scanner glob common-path)
  #'(lambda ()
      (let ((update (get-buffer-window buffer)))
        (with-set-buffer
          (save-excursion
            (set-buffer buffer)
            (if (null async-ggrep-timer-callback)
                (setq update nil)
              (let ((target (funcall glob))
                    (timer async-ggrep-timer-callback)
                    (last-tick async-ggrep-last-update)
                    file linenum-list)
                (if (consp target)
                    (progn
                      (setq file (car target))
                      (setq linenum-list (cadr target)))
                  (setq file target))
                (cond ((stringp file)
                       (with-output-to-buffer (buffer (point-max))
                         (cond ((not (ggrep-scan-files-1 file patterns temp scanner common-path linenum-list))
                                (setq update nil))
                               (update
                                (let ((tick (get-internal-real-time)))
                                  (cond ((> (- tick last-tick) 500)
                                         (set-buffer buffer)
                                         (setq async-ggrep-last-update tick))
                                        (t
                                         (setq update nil))))))
                         (start-timer 0 timer t)))
                      (file
                       (setq update nil)
                       (start-timer 0 timer t))
                      (t
                       (stop-async-ggrep)))))))
        (and update (refresh-screen)))))

(defun ggrep-scan-files-async (patterns buffer temp scanner file dirs target-list)
  (let (files dirlist common-path)
    (setq files
          (mapcar #'(lambda (target)
                      (if (consp target) (car target) target))
                  target-list))
    (if files
        (progn
          (if *ggrep-full-name*
              (setq common-path "")
            (setq common-path (glob-common-path files))))
      (progn
        (setq dirlist (glob-expand-list
                       (mapcar #'(lambda (d) (ggrep-get-setting-item d "directory"))
                               dirs)))
        (unless dirlist
          (error "~S~%僨傿儗僋僩儕偑尒偮偐傝傑偣傫" dirs))
        (setq dirlist (mapcar 'append-trail-slash dirlist))
        (dolist (dir (prog1 (nreverse dirlist) (setq dirlist nil)))
          (unless (member dir dirlist :test 'string=)
            (if dirlist
                (push dir dirlist)
              (setq dirlist (list dir)))))
        (if *ggrep-full-name*
            (setq common-path "")
          (setq common-path (if (= (length dirlist) 1)
                                (car dirlist)
                              (glob-common-path dirlist))))))
    (scan-files-setup common-path buffer temp (ggrep-find-error-scanner))
    (async-ggrep-mode)
    (setq async-ggrep-temp-buffer temp)
    (unless target-list
      (dolist (d dirs)
        (when (ggrep-get-setting-item d "enable")
          (glob-exec (glob-expand (ggrep-get-setting-item d "directory"))
                     :recursive (ggrep-get-setting-item d "subdir")
                     :file-only t :wild file
                     :absolute t
                     :callback
                     #'(lambda (f)
                         (if target-list
                             (pushnew f target-list :test 'string=)
                           (setq target-list (list f)))))))
      (setq target-list (nreverse target-list)))
    (setq async-ggrep-timer-callback
          (ggrep-async-scanner patterns buffer temp scanner
                               #'(lambda () (or (pop target-list) nil))
                               common-path))
    (start-timer 0 async-ggrep-timer-callback t)
    (setq async-ggrep-mode t)
    (setq async-ggrep-status "running")))

(defun ggrep-find-error-scanner ()
  #'(lambda (&optional limit)
      (scan-buffer (compile-regexp ".*") :limit limit)))

(defun ggrep-scanner (patterns method case-fold word-search &key (syntax t))
  (let (match-patterns nomatch-patterns pattern status fix-status)
    ;; match-patterns, nomatch-patterns ::= (pattern . status)
    ;; status: nil       僥僗僩偺幐攕偑妋掕嵪
    ;;       : t         僥僗僩偺惉岟偑妋掕嵪
    ;;       : 惓惍悢    師偵(僥僗僩偺惉斲偵娭傢傜偢)儅僢僠偑惉岟偡傞暔棟峴偺峴摢偺 point
    ;;       : 0         枹妋掕
    (dolist (p (reverse patterns))
      (if (ggrep-get-setting-item p "match")
          (push (cons (ggrep-get-setting-item p "pattern") 0) match-patterns)
        (push (cons (ggrep-get-setting-item p "pattern") 0) nomatch-patterns)))
    (setq fix-status 0)
    (cond
     ;; AND 専嶕
     ((or (eq method :and)
          (and (eq method :or)
               (= 1 (+ (length match-patterns) (length nomatch-patterns))))
          (eq method nil))
      #'(lambda (&optional limit (init :ignore))
          (block ggrep-scanner-instance
            ;; 専嶕僷僞乕儞 status 弶婜壔
            (when init
              (setq fix-status 0)
              (dolist (pattern-pair match-patterns)
                (rplacd pattern-pair 0))
              (dolist (pattern-pair nomatch-patterns)
                (rplacd pattern-pair 0))
              (if (eq init t)
                  (return-from ggrep-scanner-instance nil)))

            ;; 専嶕懳徾偑側偄応崌偼 nil
            (unless (or match-patterns nomatch-patterns)
              (return-from ggrep-scanner-instance (values nil nil)))
            (goto-bol)
            (let ((cpoint (point)) match-position-list)
              (loop
                ;; match pattern 専嶕
                (when match-patterns
                  (block ggrep-scanner-match
                    (loop
                      (setq match-position-list nil)
                      (dolist (pattern-pair match-patterns)
                        (setq pattern (car pattern-pair))
                        (setq status (cdr pattern-pair))
                        (cond
                         ;; 僥僗僩惉岟(儅僢僠惉岟)偑妋掕嵪 -> 偁傝偊側偄忬懺
                         ((eq status t)
;                          (plain-error "ggrep (ggrep-scanner)偺僄儔乕偱偡丅")
                          )
                         ;; 僥僗僩幐攕(儅僢僠幐攕)偑妋掕嵪 -> nil 傪曉偡
                         ((eq status nil)
                          (return-from ggrep-scanner-instance (values nil nil)))
                         ;; 壗傜偐偺峴偱儅僢僠
                         ((ggrep-scan-buffer pattern
                                             :case-fold case-fold
                                             :left-bound word-search
                                             :right-bound word-search
                                             :limit limit
                                             :syntax syntax)
                          (push (cons (match-beginning 0) (match-end 0)) match-position-list)
                          (goto-bol))
                         ;; 僥僗僩幐攕(儅僢僠幐攕) -> 僥僗僩幐攕妋掕忣曬傪婰榐偟丄nil 傪曉偡
                         (t
                          (rplacd pattern-pair nil)
                          (return-from ggrep-scanner-instance (values nil nil)))))
                      (if (= cpoint (point))
                          ;; 慡儅僢僠偑摨堦峴側傜 t
                          (progn
                            (setq match-position-list (nreverse match-position-list))
                            (return-from ggrep-scanner-match t))
                        ;; 峴傪堏摦偟偰偄偨傜尰嵼峴偱嵞僠僃僢僋弨旛
                        (setq cpoint (point))))))
                ;; no match pattern 専嶕
                (unless nomatch-patterns
                  (return-from ggrep-scanner-instance (values t match-position-list)))
                (block ggrep-scanner-nomatch
                  (dolist (pattern-pair nomatch-patterns)
                    (setq pattern (car pattern-pair))
                    (setq status (cdr pattern-pair))
                    (cond
                     ;; 僥僗僩惉岟(儅僢僠幐攕)偑妋掕嵪
                     ((eq status t))
                     ;; 壗傜偐偺峴偱儅僢僠
                     ((ggrep-scan-buffer pattern
                                         :case-fold case-fold
                                         :left-bound word-search
                                         :right-bound word-search
                                         :limit limit
                                         :syntax syntax)
                      (if (progn (goto-bol) (= cpoint (point)))
                          ;; 僥僗僩幐攕(懳徾峴偱儅僢僠)
                          (if (progn (goto-eol) (forward-char 1))
                              ;; 師峴傊堏摦偱偒傟偽師峴傊堏摦偟嵞僠僃僢僋弨旛
                              (return-from ggrep-scanner-nomatch nil)
                            ;; 師峴傊堏摦偱偒側偗傟偽 nil
                            (return-from ggrep-scanner-instance (values nil nil)))
                        ;; 僥僗僩惉岟(懳徾峴埲奜偱儅僢僠) -> 懳徾峴偵栠傞
                        (goto-char cpoint)))
                     ;; 僥僗僩惉岟(儅僢僠幐攕) -> 僥僗僩惉岟妋掕忣曬傪婰榐
                     (t
                      (rplacd pattern-pair t)))))
                (if (= cpoint (point))
                    (return-from ggrep-scanner-instance (values t match-position-list))
                  (setq cpoint (point))))))))
     ;; OR 専嶕
     ((eq method :or)
      #'(lambda (&optional limit (init :ignore))
          (block ggrep-scanner-instance
            ;; 専嶕僷僞乕儞 status 弶婜壔
            (when init
              (setq fix-status 0)
              (dolist (pattern-pair match-patterns)
                (rplacd pattern-pair 0))
              (dolist (pattern-pair nomatch-patterns)
                (rplacd pattern-pair 0))
              (if (eq init t)
                  (return-from ggrep-scanner-instance nil)))

            ;; 専嶕懳徾偑側偄応崌偼 nil
            (unless (or match-patterns nomatch-patterns)
              (return-from ggrep-scanner-instance (values nil nil)))
            (goto-bol)
            (let ((cpoint (point)))
              (loop
                ;; match pattern 専嶕
                (dolist (pattern-pair match-patterns)
                  (setq pattern (car pattern-pair))
                  (setq status (cdr pattern-pair))
                  (cond
                   ;; 僥僗僩幐攕(儅僢僠幐攕)偑妋掕嵪 -> 師偺僷僞乕儞偺僥僗僩傊
                   ((eq status nil))
                   ;; 僥僗僩惉岟(儅僢僠惉岟)偑妋掕嵪 -> 偁傝偊側偄忬懺
                   ((eq status t)
;                    (plain-error "ggrep (ggrep-scanner)偺僄儔乕偱偡丅")
                    (return-from ggrep-scanner-instance
                      (values t (list (cons (match-beginning 0) (match-end 0))))))
                   ;; 師偺儅僢僠惉岟 point 偵枮偨側偄応崌 -> nil 傪曉偡
                   ((and (integerp status) (< cpoint status)))
                   ;; 壗傜偐偺峴偱儅僢僠
                   ((ggrep-scan-buffer pattern
                                       :case-fold case-fold
                                       :left-bound word-search
                                       :right-bound word-search
                                       :limit limit
                                       :syntax syntax)
                    (if (progn (goto-bol) (= cpoint (point)))
                        ;; 尰嵼峴偱儅僢僠
                        (progn
                          (rplacd pattern-pair 0)
                          (return-from ggrep-scanner-instance
                            (values t (list (cons (match-beginning 0) (match-end 0))))))
                      ;; 尰嵼峴埲奜偱儅僢僠 -> 儅僢僠億僀儞僩傪婰榐
                      (progn
                        (rplacd pattern-pair (point))
                        (goto-char cpoint))))
                   ;; 僥僗僩幐攕(儅僢僠幐攕) -> 僥僗僩幐攕妋掕忣曬傪婰榐
                   (t
                    (rplacd pattern-pair nil))))
                ;; no match pattern 専嶕
                (dolist (pattern-pair nomatch-patterns)
                  (setq pattern (car pattern-pair))
                  (setq status (cdr pattern-pair))
                  (cond
                   ;; 僥僗僩幐攕(儅僢僠惉岟)偑妋掕嵪 -> 偁傝偊側偄忬懺
                   ((eq status nil))
                   ;; 僥僗僩惉岟(儅僢僠幐攕)偑妋掕嵪 -> t 傪曉偡
                   ((eq status t)
                    (return-from ggrep-scanner-instance t))
                   ;; 師偺儅僢僠惉岟 point 偵枮偨側偄応崌(僥僗僩惉岟) -> t 傪曉偡
                   ((and (integerp status) (< cpoint status))
                    (return-from ggrep-scanner-instance t))
                   ;; 壗傜偐偺峴偱儅僢僠
                   ((ggrep-scan-buffer pattern
                                       :case-fold case-fold
                                       :left-bound word-search
                                       :right-bound word-search
                                       :limit limit
                                       :syntax syntax)
                    (goto-bol)
                    (if (/= cpoint (point))
                        ;; 僥僗僩惉岟(尰嵼峴偱儅僢僠幐攕) -> 儅僢僠惉岟 point 忣曬傪婰榐偟丄t 傪曉偡
                        (progn
                          (rplacd pattern-pair (point))
                          (goto-char cpoint)
                          (return-from ggrep-scanner-instance t))
                      ;; 僥僗僩幐攕(尰嵼峴偱儅僢僠惉岟)
                      (progn
                        (rplacd pattern-pair 0)
                        (goto-char cpoint))))
                   ;; 僥僗僩惉岟(儅僢僠幐攕)偑妋掕 -> 僥僗僩惉岟妋掕忣曬傪婰榐偟丄t 傪曉偡
                   (t
                    (rplacd pattern-pair t)
                    (return-from ggrep-scanner-instance t))))
                ;; 忦審偵晄堦抳
                (if (progn (goto-eol) (forward-char 1))
                    (setq cpoint (point))
                  (return-from ggrep-scanner-instance nil)))))))
     )))

(defun ggrep-scan-buffer (pattern &key
                                  case-fold left-bound right-bound limit (syntax t)
                                  regexp
;                                  no-dup reverse tail last-match
                                  )
  (let (current-syntax)
    (when (eq syntax nil)
      (return-from ggrep-scan-buffer nil))
    (loop
      (unless (scan-buffer pattern
                           :case-fold case-fold :left-bound left-bound :right-bound right-bound
                           :limit limit :regexp regexp
;                          :no-dup no-dup  :reverse reverse :tail tail :last-match last-match
                           )
        (return-from ggrep-scan-buffer nil))
      (when (or (eq syntax t)
                (member (setq current-syntax (parse-point-syntax)) syntax))
        (return-from ggrep-scan-buffer t))
      ;; :tag 偺偁傞儌乕僪偱偺 syntax 偺曄壔偵拲堄
      ;; < > 偺娫偵 :string :comment 偑弌尰偡傞
      (cond
       ;; :string 偺奐巒傑偱堏摦
       ((equal syntax '(:string))
        (skip-syntax-spec-forward "^\"")
        (forward-char 1))
       ;; :string 偺廔椆傑偱堏摦
       ((eq current-syntax :string)
        (skip-syntax-spec-forward "^\"")
        (forward-char 1))
       ;; 偦偺懠
       (t
        (forward-char 1))))))

(defun ggrep-patterns-normalization (patterns &key regexp-search understand-escape-sequences)
  (setq patterns (copy-tree patterns))
  (let (tmp-patterns)
    ;; 扨弮暥帤楍儕僗僩偺曄峏 (愭摢梫慺偺傒偺妋擣偱敾掕)
    (if (stringp (car patterns))
        (setq patterns
              (mapcar #'(lambda (pattern)
                          (list (list (copy-string "enable") t)
                                (list (copy-string "pattern") pattern)
                                (list (copy-string "match") t)))
                      patterns)))
    ;; 晄梫丒揔愗偱側偄僷僞乕儞偺攔彍
    (dolist (p (nreverse patterns))
      (if (and (eq (ggrep-get-setting-item p "enable") t)
               (or (regexpp (ggrep-get-setting-item p "pattern"))
                   (and (stringp (ggrep-get-setting-item p "pattern"))
                        (string/= (ggrep-get-setting-item p "pattern") ""))))
          (push p tmp-patterns)))
    (setq patterns tmp-patterns)
    (setq tmp-patterns nil)
    ;; 僄僗働乕僾僔乕働儞僗
    (when understand-escape-sequences
      (dolist (p (reverse patterns))
        (push
         (list
          (list (copy-string "enable") (ggrep-get-setting-item p "enable"))
          (list (copy-string "pattern")
                (decode-escape-sequence
                 (ggrep-get-setting-item p "pattern") regexp-search))
          (list (copy-string "match") (ggrep-get-setting-item p "match")))
         tmp-patterns))
      (setq patterns tmp-patterns)
      (setq tmp-patterns nil))
    ;; 惓婯昞尰
    (when regexp-search
      (dolist (p (nreverse patterns))
        (push (list (list (copy-string "enable") (ggrep-get-setting-item p "enable"))
                    (list (copy-string "pattern")
                          (if (regexpp (ggrep-get-setting-item p "pattern"))
                              (ggrep-get-setting-item p "pattern")
                            (compile-regexp (ggrep-get-setting-item p "pattern")
                                            *ggrep-case-fold-search*)))
                    (list (copy-string "match") (ggrep-get-setting-item p "match")))
              tmp-patterns))
      (setq patterns tmp-patterns)
      (setq tmp-patterns nil))
    patterns))

(defun ggrep-dirs-normalization (dirs)
  (setq dirs (copy-tree dirs))
  (let (tmp-dirs)
    (if (stringp (car dirs))
        (setq dirs
              (mapcar #'(lambda (dir)
                          (list (list (copy-string "enable") t)
                                (list (copy-string "directory") dir)
                                (list (copy-string "subdir") nil)))
                      dirs)))
    (dolist (d (nreverse dirs))
      (if (and (eq (ggrep-get-setting-item d "enable") t)
               (string/= (ggrep-get-setting-item d "directory") ""))
          (if (string= (ggrep-get-setting-item d "directory") "<僇儗儞僩僨傿儗僋僩儕>")
              (push (list (assoc "enable" d :test 'string=)
                          (list (copy-string "directory") (default-directory))
                          (assoc "subdir" d :test 'string=)) tmp-dirs)
            (push d tmp-dirs))))
    (setq dirs tmp-dirs)
    (setq tmp-dirs nil))
  dirs)

(defun ggrep-scan-files (patterns method file dirs &optional async target-list)
  (long-operation
    (setq patterns (ggrep-patterns-normalization
                    patterns
                    :regexp-search *ggrep-regexp-search*
                    :understand-escape-sequences nil))
    (setq dirs (ggrep-dirs-normalization dirs))
    (let ((buffer (get-buffer-create
                   (if *ggrep-contents-only*
                       *ggrep-contents-only-bufname*
                     "*ggrep*")))
          tmp-patterns)
      (when (save-excursion
              (set-buffer buffer)
              async-ggrep-timer-callback)
        (if (yes-or-no-p "ggrep偼偡偱偵摦嶌拞偱偡丅巰側偡?")
            (save-excursion
              (set-buffer buffer)
              (stop-async-ggrep))
          (quit)))
      (let ((temp (create-new-buffer "*ggrep temp*"))
            (scanner (ggrep-scanner patterns method *ggrep-case-fold-search*
                                    *ggrep-word-search*))); file 偵懳偟偰偼 syntax 巜掕側偟
        (if async
            (ggrep-scan-files-async patterns buffer temp scanner file dirs target-list)
          (ggrep-scan-files-sync patterns buffer temp scanner file dirs target-list))))))

(defun ggrep1 (patterns method arg &key (regexp-search *ggrep-regexp-search*)
                                        (case-fold *ggrep-case-fold-search*)
                                        (word-search *ggrep-word-search*)
                                        (contents-only *ggrep-contents-only*)
                                        (syntax *ggrep-syntax*)
                                        name-only)
  "僶僢僼傽懳徾 ggrep 撪晹娭悢
arg: t                   : 僇儗儞僩僶僢僼傽
     nil                 : 僶僢僼傽儕僗僩
     [懳徾僶僢僼傽 or (list 懳徾僶僢僼傽 峴斣崋儕僗僩)] 偺儕僗僩"
  (long-operation
    (let (buffer linenum-list work-arg
          contents-only-buffer contents-only-buffer-target-p
          contents-only-work-buffer)
      ;; 僷僞乕儞偺昗弨壔
      (setq patterns (ggrep-patterns-normalization
                      patterns
                      :regexp-search regexp-search
                      :understand-escape-sequences nil))
      ;; 専嶕僶僢僼傽偺昗弨壔
      (cond
       ((eq arg t)
        (setq arg (list (selected-buffer))))
       ((null arg)
        (dolist (buffer (buffer-list))
          (unless (string-match "^ " (buffer-name buffer))
            (push buffer arg)))
        (setq arg (nreverse arg)))
       (t
        (setq work-arg nil)
        (dolist (target arg)
          (cond
           ((bufferp target)
            (push target work-arg))
           ((and (consp target) (bufferp (car target)))
            (push target work-arg))
           ((and (stringp target) (bufferp (setq buffer (find-buffer target))))
            (push buffer work-arg))
           ((and (consp target) (stringp (car target))
                 (bufferp (setq buffer (find-buffer (car target)))))
            (setq linenum-list (cadr target))
            (push (list buffer linenum-list) work-arg))
           (t
            (push target work-arg))))
        (setq arg (nreverse work-arg))))
      (unwind-protect
          (progn
            ;; *ggrep-contents-only-bufname* 偑専嶕僶僢僼傽偩偭偨応崌偺媬嵪慬抲
            (when (and contents-only
                       (setq contents-only-buffer (find-buffer *ggrep-contents-only-bufname*)))
              ;; 媬嵪昁梫惈偺妋擣
              (dolist (target arg)
                (cond
                 ((bufferp target)
                  (setq buffer target))
                 ((and (consp target) (bufferp (car target)))
                  (setq buffer (car target))))
                (when (eq buffer contents-only-buffer)
                  (setq contents-only-buffer-target-p t)
                  (return)))
              (when contents-only-buffer-target-p
                ;; 戙懼偺僶僢僼傽偺嶌惉
                (setq contents-only-work-buffer (create-new-buffer " *ggrep work*"))
                (setup-temp-buffer contents-only-work-buffer)
                (save-excursion
                  (set-buffer contents-only-buffer)
                  (with-output-to-buffer (contents-only-work-buffer)
                    (format t "~A" (buffer-substring (point-min) (point-max)))))
                ;; 戙懼僶僢僼傽傊偺僞乕僎僢僩曄峏
                (setq work-arg nil)
                (dolist (target arg)
                  (cond
                   ((bufferp target)
                    (if (eq target contents-only-buffer)
                        (push contents-only-work-buffer work-arg)
                      (push target work-arg)))
                   ((and (consp target) (bufferp (car target)))
                    (setq buffer (car target))
                    (setq linenum-list (cadr target))
                    (if (eq buffer contents-only-buffer)
                        (push (list contents-only-work-buffer linenum-list) work-arg)
                      (push target work-arg)))))
                (setq arg (nreverse work-arg))))

            (with-output-to-temp-buffer ((if contents-only
                                             *ggrep-contents-only-bufname*
                                           "*compilation*"))
              (let ((sbuffer (buffer-stream-buffer *standard-output*))
                    (scanner (ggrep-scanner patterns method case-fold word-search :syntax syntax)))
                (save-excursion
                  (set-buffer sbuffer)
                  (make-local-variable '*find-error-scanner*)
                  (setq *find-error-scanner* (ggrep-find-error-scanner))
                  (set-buffer-fold-width nil sbuffer)
                  (dolist (target arg)
                    (setq buffer nil
                          linenum-list nil)
                    (cond
                     ((bufferp target)
                      (setq buffer target))
                     ((and (consp target) (bufferp (car target)))
                      (setq buffer (car target))
                      (setq linenum-list (cadr target))))
                    (let ((bufname (buffer-name buffer)))
                      (unless (eq buffer sbuffer)
                        (message "Scanning (~A)" bufname)
                        (set-buffer buffer)
                        (save-excursion
                          (goto-char (point-min))
                          (cond (name-only ; linenum-list 柍帇
                                 (when (funcall scanner)
                                   (format t "<~A>~%" bufname)
                                   t))
                                (t
                                 (ggrep-scan-file (concatenate 'string "<" bufname ">")
                                                  scanner "" linenum-list)))))))))))
        (when contents-only-work-buffer
          (delete-buffer contents-only-work-buffer))))
    (run-hooks '*ggrep-hook*)
    (message "completed.")
    t))

(defun ggrep-narrow-buffer-list (&optional all)
  (let (narrow-buffer-list other-buffer-list)
    (save-excursion
      (dolist (buffer (buffer-list))
        (set-buffer buffer)
        (if (and ed::*find-error-scanner*
                 (string/= (buffer-name buffer) *ggrep-contents-only-bufname*))
            (push buffer narrow-buffer-list)
          (unless (string-match "^ " (buffer-name buffer))
            (push buffer other-buffer-list)))))
    (setq narrow-buffer-list (nreverse narrow-buffer-list))
    (when all
      (setq narrow-buffer-list
            (nconc narrow-buffer-list (nreverse other-buffer-list))))
    narrow-buffer-list))

(defun ggrep-get-buffer-list-by-buffer-regexp-list (buffer-regexp-list)
  (let (buffer-list)
    (dolist (buffer-regexp buffer-regexp-list)
      (when (ggrep-regexp-valid-p buffer-regexp)
        (unless (regexpp buffer-regexp)
          (setq buffer-regexp (compile-regexp buffer-regexp)))
        (dolist (buffer (buffer-list))
          (setq buffer-name (buffer-name buffer))
          (when (and (not (string-match "^ " buffer-name))
                     (string-match buffer-regexp buffer-name))
            (pushnew buffer buffer-list)))))
    (nreverse buffer-list)))

(defun ggrep-get-target-list (buffer &optional narrow-unit)
  "ggrep 僞乕僎僢僩儕僗僩傪 buffer 偐傜庢摼
栠傝抣: <TARGET-LIST>
  <TARGET-LIST>           ::= (<TARGET>*)
  <TARGET>                ::= <TARGETOBJ>
                            | (<TARGETOBJ> <LINENUM-LIST>)
  <TARGETOBJ>             ::= <BUFFER>
                            | <FILE-PATH>
  <LINENUM-LIST>          ::= (<LINENUM>*)"
  (when (and (bufferp buffer)
             (not (deleted-buffer-p buffer)))
    (let ((regexp (compile-regexp "^\\(.+?\\):\\([1-9][0-9]*\\):" t))
          default-directory target target-list targetstr pre-targetstr
          targetstr targetobj targetstr-and-linenum linenum linenum-list)
      (flet ((get-targetstr-and-linenum ()
               (when (scan-buffer "^." :regexp t)
                 (if (looking-at regexp)
                     (cons (match-string 1) (read-from-string (match-string 2)))
                   (cons (buffer-substring (point) (progn (goto-eol) (point))) nil)))))
        (save-excursion
          (set-buffer buffer)
          (setq default-directory (default-directory))
          (goto-char (point-min))
          ;; 枅峴庢摼
          (while (and (setq targetstr-and-linenum (get-targetstr-and-linenum))
                      (setq targetstr (car targetstr-and-linenum))
                      (string/= targetstr ""))
            (if (not (eq narrow-unit :buffer))
                (setq linenum (cdr targetstr-and-linenum))
              (setq linenum nil))
            (if (string-not-equal targetstr pre-targetstr)
                ;; 僶僢僼傽/僼傽僀儖偑愗傝懼傢傞応崌
                (progn
                  ;; 1 峴栚偱側偄応崌
                  (when pre-targetstr
                    (if (string-match "^<\\(.+\\)>$" pre-targetstr)
                        (setq targetobj (find-buffer (match-string 1)))
                      (setq targetobj (merge-pathnames pre-targetstr default-directory)))
                    (when targetobj
                      (if linenum-list
                          (push (list targetobj (nreverse linenum-list)) target-list)
                        (push targetobj target-list))))
                  (setq pre-targetstr targetstr)
                  (setq targetstr nil)
                  (setq targetobj nil)
                  (setq linenum-list nil)
                  (when linenum
                    (push linenum linenum-list)))
              ;; 摨堦僶僢僼傽/僼傽僀儖偺応崌
              (when linenum
                (push linenum linenum-list)))
            (goto-eol)
            (forward-char))
          (when pre-targetstr
            (if (string-match "^<\\(.+\\)>$" pre-targetstr)
                (setq targetobj (find-buffer (match-string 1)))
              (setq targetobj (merge-pathnames pre-targetstr default-directory)))
            (when targetobj
              (if linenum-list
                  (push (list targetobj (nreverse linenum-list)) target-list)
                (push targetobj target-list))))
          (nreverse target-list))))))

(defun ggrep-regexp-valid-p (regexp)
  (cond
   ((regexpp regexp)
    t)
   ((and (stringp regexp)
         (or (string= regexp "")
             (handler-case
                 (compile-regexp regexp)
               (error (c) nil))))
    t)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ggrep-read-patterns (&key command-name
                                 (patterns nil patterns-sv)
                                 (method nil method-sv)
                                 (regexp-search nil regexp-search-sv)
                                 (nomatch-search-use nil nomatch-search-use-sv)
                                 (default-pattern-support nil default-pattern-support-sv))
  "nomatch-search-use 偺抣偵傛偭偰丄曉偡 patterns 偺僼僅乕儅僢僩偑曄壔偡傞丅
nomatch-search-use 偑 nil 偺応崌偼僔儞僾儖側暥帤楍偺儕僗僩傪曉偟丄
non-nil 偺応崌偼 \"enable\" \"pattern\" \"match\" 偺 3 梫慺偐傜側傞
崁栚偺儕僗僩傪曉偡丅"
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))

  ;; method 巜掕
  (unless method-sv
    (let ((method-name-list (mapcar #'(lambda (m) (string-downcase (car m)))
                                    *ggrep-method-alist*)))
      (setq method
            (cdr (assoc
                  (completing-read
                   (format nil "~Amethod (~A): "
                           command-name
                           (subseq (format nil "~{ / ~A~}" method-name-list) 3))
                   method-name-list
                   :case-fold t
                   :default (string-downcase
                             (or (car (find *last-ggrep-method* *ggrep-method-alist* :key #'cdr))
                                 (caar *ggrep-method-alist*)))
                   :must-match t)
                  *ggrep-method-alist* :test #'string-equal)))))

  (unless patterns-sv
    (let ((i 1) match)
      ;; 惓婯昞尰 or 暥帤楍 専嶕偺慖戰
      (unless regexp-search-sv
        (setq regexp-search
              (string-equal
               "regexp"
               (completing-read
                (format nil "~Apattern-type (regexp / string): " command-name)
                '("regexp" "string")
                :default (if *ggrep-regexp-search* "regexp" "string")
                :case-fold t
                :must-match t))))
      ;; nomatch 専嶕傪峴偆偐
      (unless nomatch-search-use-sv
        (setq nomatch-search-use
              (string-equal
               "yes"
               (completing-read
                (format nil "~Ause nomatch-search? (yes / no): " command-name)
                '("yes" "no")
                :default "no"
                :case-fold t
                :must-match t))))
      ;; patterns 巜掕
      (setq match t)
      (loop
        (if nomatch-search-use
            (message "pattern(s)~A:~{ ~A~}"
                     (if method
                         (format nil " [~A]"
                                 (car (find method *ggrep-method-alist* :key #'cdr)))
                       "")
                     (mapcar #'(lambda (x)
                                 (format nil "(~S . ~S)"
                                         (cadr (assoc "pattern" x :test #'string=))
                                         (cadr (assoc "match" x :test #'string=))))
                             (reverse patterns)))
          (message "pattern(s)~A:~{ ~S~}"
                   (if method
                       (format nil " [~A]"
                               (car (find method *ggrep-method-alist* :key #'cdr)))
                     "")
                   (reverse patterns)))
        (setq pattern
              (if regexp-search
                  (read-string
                   (format nil "~A(~D)~A regexp: "
                           command-name i
                           (if method
                               (format nil " [~A]"
                                       (car (find method *ggrep-method-alist* :key #'cdr)))
                             ""))
                   :default (when default-pattern-support
                              (let ((regexp (nth (1- i) *last-ggrep-regexp-list*)))
                                (when (listp regexp)
                                  (setq regexp (cadr (assoc "pattern" regexp :test #'string=))))
                                (cond ((regexpp regexp)
                                       (compiled-regexp-source regexp))
                                      ((stringp regexp)
                                       regexp)
                                      (t
                                       ""))))
                   :history 'search)
                (read-string
                 (format nil "~A(~D)~A string: "
                         command-name i
                         (if method
                             (format nil " [~A]"
                                     (car (find method *ggrep-method-alist* :key #'cdr)))
                           ""))
                 :default (when default-pattern-support
                            (let ((string (nth (1- i) *last-fggrep-pattern-list*)))
                              (when (listp string)
                                (setq string (cadr (assoc "pattern" string :test #'string=))))
                              (if (stringp string)
                                  string "")))
                 :history 'search)))
        (cond
         ((string= pattern "")
          (return))
         ((and regexp-search (not (ggrep-regexp-valid-p pattern)))
          (message "pattern invalid regexp: ~A" pattern)
          (sleep-for 1))
         (t
          (if nomatch-search-use
              (progn
                (setq match
                      (string-equal
                       "match"
                       (completing-read
                        (format nil "~A(~D) [~A] (match / nomatch): "
                                command-name i pattern)
                        '("match" "nomatch")
                        :default (if match "match" "nomatch")
                        :case-fold t
                        :must-match t)))
                (push (list (list "enable" t)
                            (list "pattern" pattern)
                            (list "match" match))
                      patterns))
            (push pattern patterns))
          (incf i))))
      (setq patterns (nreverse patterns))))
  (values patterns method regexp-search nomatch-search-use))

(defun ggrep-read-dirs (&key command-name
                             (dirs nil dirs-sv)
                             (files nil files-sv)
                             (subdir-constant nil subdir-constant-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))

  (let (dir subdir (i 1))
    (unless dirs-sv
      (setq dir (default-directory))
      (setq subdir *ggrep-subdir-default*)
      (loop
        (setq dir
              (read-directory-name
               (format nil "~A(~D) directory: " command-name i)
               :default (append-trail-slash dir)))
        ;; (read-directory-name) 偱偼嬻暥帤楍偑擖椡偝傟偨応崌丄
        ;; (default-directory) ? 偺擖椡偲敾抐偝傟丄嬻暥帤楍偑擖椡偝傟偨偙偲偼
        ;; 擣幆偱偒側偄丅
        (if subdir-constant-sv
            (setq subdir subdir-constant-sv)
          (setq subdir
                (string-equal
                 "yes"
                 (completing-read
                  (format nil "~A(~D) [~A] subdir? (yes / no): "
                          command-name i (append-trail-slash dir))
                  '("yes" "no")
                  :default (if subdir "yes" "no")
                  :case-fold t
                  :must-match t))))
        (push (list (list "enable" t)
                    (list "directory" dir)
                    (list "subdir" subdir))
              dirs)
        (unless (string-equal
                 "yes"
                 (completing-read
                  (format nil "~Adirectory add? (yes / no): " command-name)
                  '("yes" "no")
                  :default "yes"
                  :case-fold t
                  :must-match t))
          (return))
        (incf i))
      (setq dirs (nreverse dirs)))
    (unless files-sv
      (setq files (read-string
                   (format nil "~Afiles: " command-name))))
    (unless files
      (setq files ""))
    (values dirs files)))

(defun ggrep-read-file-list (&key command-name
                                  (file-list nil file-list-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))
  ;;
  (let ((i 1) (dir (default-directory)) file)
    (unless file-list-sv
      (loop
        (setq file
              (read-file-name
               (format nil "~A(~D) file: " command-name i)
               :default (append-trail-slash dir)))
        (setq dir (directory-namestring file))
        ;; (read-file-name) 偱偼嬻暥帤楍擖椡晄壜
        (pushnew file file-list :test #'string-equal)
        (unless (string-equal
                 "yes"
                 (completing-read
                  (format nil "~Afile add? (yes / no): " command-name)
                  '("yes" "no")
                  :default "yes"
                  :case-fold t
                  :must-match t))
          (return))
        (incf i))
      (setq file-list (nreverse file-list)))
    file-list))

(defun ggrep-read-buffer-list (&key command-name
                                    (buffer-list nil buffer-list-sv)
                                    (output-name t output-name-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))
  ;;
  (let ((i 1) buffer-name buffer-name-list)
    (unless buffer-list-sv
      (dolist (buffer (buffer-list))
        (unless (string-match "^ " (buffer-name buffer))
          (push (buffer-name buffer) buffer-name-list)))
      (while buffer-name-list
        (message "target buffer(s):~{ \"~A\"~}"
                 (mapcar #'buffer-name (reverse buffer-list)))
        (setq buffer-name
              (completing-read
               (format nil "~A(~D) buffer: " command-name i)
               buffer-name-list
               :default (if (member (buffer-name (selected-buffer)) buffer-name-list
                                    :test #'string=)
                            (buffer-name (selected-buffer)) "")))
        (when (string= buffer-name "")
          (return))
        (when (find-buffer buffer-name)
          (push (find-buffer buffer-name) buffer-list))
        (setq buffer-name-list
              (delete buffer-name buffer-name-list :test #'string=))
        (incf i))
      (setq buffer-list (nreverse buffer-list))))
  (when (and output-name (listp buffer-list))
    (setq buffer-list (mapcar #'(lambda (x) (if (bufferp x) (buffer-name x) x))
                              buffer-list)))
  buffer-list)

(defun ggrep-read-narrow (&key command-name
                               (narrow-buffer nil narrow-buffer-sv)
                               (narrow-unit nil narrow-unit-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))
  ;;
  (unless narrow-buffer-sv
    (setq narrow-buffer
          (completing-read
           (format nil "~Anarrow buffer: " command-name)
           (mapcar #'buffer-name (ggrep-narrow-buffer-list))
           :default (buffer-name (selected-buffer)))))
  (unless narrow-unit-sv
    (setq narrow-unit
          (if (string-equal
               "line"
               (completing-read
                (format nil "~Anarrow unit (line / buffer(file)): " command-name)
                '("line" "buffer")
                :default (if (not (eq *ggrep-narrow-buffer* :buffer))
                             "line" "buffer")
                :must-match t))
              :line nil)))
  (when (stringp narrow-buffer)
    (setq narrow-buffer (find-buffer narrow-buffer)))
  (values narrow-buffer narrow-unit))

(defun ggrep-read-buffer-regexp-list (&key command-name
                                           (buffer-regexp-list nil buffer-regexp-list-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))
  ;;
  (let ((i 1) buffer-list buffer-regexp buffer-name)
    (if buffer-regexp-list-sv
        (setq buffer-list
              (ggrep-get-buffer-list-by-buffer-regexp-list buffer-regexp-list))
      (progn
        (loop
          (message "target buffer(s):~{ \"~A\"~}"
                   (mapcar #'buffer-name (reverse buffer-list)))
          (setq buffer-regexp
                (read-string
                 (format nil "~A(~D) buffer-regexp: " command-name i)))
          (when (string= buffer-regexp "")
            (return))
          (when (ggrep-regexp-valid-p buffer-regexp)
            (pushnew buffer-regexp buffer-regexp-list :test #'string=)
            (setq buffer-regexp (compile-regexp buffer-regexp))
            (dolist (buffer (buffer-list))
              (setq buffer-name (buffer-name buffer))
              (when (and (not (string-match "^ " buffer-name))
                         (string-match buffer-regexp buffer-name))
                (pushnew buffer buffer-list))))
          (incf i))
        (setq buffer-regexp-list (nreverse buffer-regexp-list))
        (setq buffer-list (nreverse buffer-list))))
    (values buffer-regexp-list buffer-list)))

(defun ggrep-read-encoding-name (&key command-name
                                      (encoding-name nil encoding-name-sv)
                                      (encoding-check-file nil encoding-check-file-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))
  ;;
  (let ((encoding-name-list (mapcar 'char-encoding-name *char-encoding-list*)))
    (unless encoding-name-sv
      (setq encoding-name
            (completing-read
             (format nil "~Aencoding: " command-name)
             encoding-name-list
             :case-fold nil
             :default (if (char-encoding-p *expected-fileio-encoding*)
                          (char-encoding-name *expected-fileio-encoding*) "")
             :must-match t)))
    (unless (find encoding-name encoding-name-list :test #'string=)
      (setq encoding-name nil))
    ;; encoding-check-file
    (unless encoding-check-file-sv
      (when encoding-name
        (setq encoding-check-file
              (string-equal
               "yes"
               (completing-read
                (format nil "~Ascan files on the disk (not on buffers)? (yes / no): " command-name)
                '("yes" "no")
                :case-fold t
                :default (if *ggrep-encoding-check-file* "yes" "no")
                :must-match t)))))
    (values encoding-name encoding-check-file)))

(defun ggrep-read-syntax (&key command-name
                               (syntax nil syntax-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))
  (let ((syntax-symbol-alist '((:string  . "string")
                               (:comment . "comment")
                               (:tag     . "tag")
                               (nil      . "misc")))
        syntax-name)
    (unless syntax-sv
      (if (string-equal
           "yes"
           (completing-read
            (format nil "~Aall syntax? (yes / no): " command-name)
            '("yes" "no")
            :default "yes"
            :case-fold t
            :must-match t))
          (setq syntax t)
        (dolist (x syntax-symbol-alist)
          (message "syntax(s):~{ \"~A\"~}" (reverse syntax))
          (if (string-equal
               "yes"
               (completing-read
                (format nil "~A~A syntax: " command-name (cdr x))
                '("yes" "no")
                :default "yes"
                :case-fold t
                :must-match t))
              (push (car x) syntax)))))
    syntax))

(defun ggrep-read-others (&key command-name
                               (case-fold *ggrep-case-fold-search* case-fold-sv)
                               (word-search *ggrep-word-search* word-search-sv)
                               (async *ggrep-async* async-sv)
                               (contents-only *ggrep-contents-only* contents-only-sv)
                               (name-only *ggrep-name-only* name-only-sv)
                               (full-name *ggrep-full-name* full-name-sv)
                               ;; --- 敾掕梡曄悢 ---
                               (regexp-search nil regexp-search-sv)
                               (buffer-only-p nil buffer-only-p-sv))
  ;; command-name
  (if (not (stringp command-name))
      (setq command-name "")
    (unless (string-match " $" command-name)
      (setq command-name (concat command-name " "))))

  ;; case-fold
  (unless case-fold-sv
    (setq case-fold
          (completing-read
           (format nil "~Acase-fold (yes / no / smart): " command-name)
           '("yes" "no" "smart")
           :case-fold t
           :default (cond ((eq *ggrep-case-fold-search* :smart) "smart")
                          (*ggrep-case-fold-search*             "yes")
                          (t                                    "no"))
           :must-match t))
    (cond
     ((string-equal case-fold "yes")
      (setq case-fold t))
     ((string-equal case-fold "no")
      (setq case-fold nil))
     (t
      (setq case-fold :smart))))
  ;; word-search
  (if regexp-search
      (setq word-search nil)
    (unless word-search-sv
      (setq word-search
            (string-equal
             "yes"
             (completing-read
              (format nil "~Aword-search (yes / no): " command-name)
              '("yes" "no")
              :case-fold t
              :default (if *ggrep-word-search* "yes" "no")
              :must-match t)))))
  ;; async
  (unless async-sv
    (unless buffer-only-p
      (setq async
            (string-equal
             "yes"
             (completing-read
              (format nil "~Aasync (yes / no): " command-name)
              '("yes" "no")
              :case-fold t
              :default (if *ggrep-async* "yes" "no")
              :must-match t)))))
  ;; contents-only
  (unless contents-only-sv
    (setq contents-only
          (string-equal
           "yes"
           (completing-read
            (format nil "~Acontents-only (yes / no): " command-name)
            '("yes" "no")
            :case-fold t
            :default (if *ggrep-contents-only* "yes" "no")
            :must-match t))))
  ;; name-only
  (unless contents-only
    (unless name-only-sv
      (setq name-only
            (string-equal
             "yes"
             (completing-read
              (format nil "~Aname-only (yes / no): " command-name)
              '("yes" "no")
              :case-fold t
              :default (if *ggrep-name-only* "yes" "no")
              :must-match t)))))
  ;; full-name
  (unless contents-only
    (unless full-name-sv
      (unless buffer-only-p
        (setq full-name
              (string-equal
               "yes"
               (completing-read
                (format nil "~Afull-name (yes / no): " command-name)
                '("yes" "no")
                :case-fold t
                :default (if *ggrep-full-name* "yes" "no")
                :must-match t))))))
  (values case-fold word-search async contents-only name-only full-name))

(defun ggrep-internal (&key
                       ;; ---------- 専嶕僷僞乕儞 ----------
                       (method nil method-sv)
                       (patterns nil patterns-sv)
                       (regexp-search *ggrep-regexp-search* regexp-search-sv)
                       ;; ---------- 専嶕懳徾 ----------
                       ; 1. 擟堄偺専嶕懳徾巜掕偑壜擻
                       (target-list nil target-list-sv)
                       ; 2. 峣崬傒懳徾僶僢僼傽 & 峣崬傒扨埵
                       (narrow-buffer nil narrow-buffer-sv)
                       (narrow-unit nil narrow-unit-sv)
                       ; 3. 僶僢僼傽捈愙巜掕 (t, nil, buffer-list)
                       (buffer-list nil buffer-list-sv)
                       ; 4. 僶僢僼傽惓婯昞尰巜掕
                       (buffer-regexp-list nil buffer-regexp-list-sv)
                       ; 5. 僼傽僀儖捈愙巜掕
                       (file-list nil file-list-sv)
                       ; 6. 僨傿儗僋僩儕柤 & 僼傽僀儖柤僷僞乕儞
                       (dirs nil dirs-sv)
                       (files nil files-sv)
                       ;; ----------
                       (encoding-name nil encoding-name-sv)
                       (encoding-check-file nil encoding-check-file-sv)
                       (syntax t syntax-sv)
                       (case-fold *ggrep-case-fold-search* case-fold-sv)
                       (word-search *ggrep-word-search* word-search-sv)
                       (async *ggrep-async* async-sv)
                       (contents-only *ggrep-contents-only* contents-only-sv)
                       (name-only *ggrep-name-only* name-only-sv)
                       (full-name *ggrep-full-name* full-name-sv))
  "堷悢桪愭弴埵
target-list   巜掕帪: files, dirs, buffer-list, narrow-buffer, narrow-unit 柍岠
narrow-buffer 巜掕帪: files, dirs, buffer-list 柍岠
buffer-list   巜掕帪: files, dirs 柍岠

history 曄悢傊偺抣曐懚偼峴傢側偄偨傔丄曐懚偡傋偒抣偼屇傃弌偟尦偱曐懚偡傞丅"
  (let (args target-type buffer-only-p)
    ;; ------------------------------------------------------------
    ;; 専嶕懳徾敾掕
    (cond
     (target-list-sv
      (setq target-type "<target-list>"))
     (narrow-buffer-sv
      (setq target-type "narrow"))
     (buffer-list-sv
      (setq target-type "buffer"))
     (buffer-regexp-list-sv
      (setq target-type "buffer-regexp"))
     (file-list-sv
      (setq target-type "file"))
     (dirs-sv
      (setq target-type "dir")))

    ;; 専嶕懳徾巜掕偐傜嬶懱揑側懳徾偺摿掕
    (cond
     ;; 暋悢僶僢僼傽巜掕 -> buffer-list
     ((string= target-type "buffer"))
     ;; 慡僶僢僼傽巜掕 -> buffer-list
     ((string= target-type "all-buffers"))
     ;; 僶僢僼傽惓婯昞尰巜掕 -> buffer-list
     ((string-equal target-type "buffer-regexp")
      (setq buffer-list
            (ggrep-get-buffer-list-by-buffer-regexp-list buffer-regexp-list)))
     ;; 僨傿儗僋僩儕巜掕 -> dirs, files
     ((string-equal target-type "dir"))
     ;; 暋悢僼傽僀儖巜掕 -> file-list
     ((string-equal target-type "file"))
     ;; 峣崬傒専嶕 -> target-list
     ((string-equal target-type "narrow")
      (setq target-list
            (ggrep-get-target-list narrow-buffer narrow-unit))))

    ;; 専嶕懳徾偑 buffer 偺傒偱偁傞偐斲偐僠僃僢僋
    (cond
     ((or target-list-sv target-list)
      (unless (find-if-not #'(lambda (x)
                               (or (bufferp x)
                                   (and (stringp x) (find-buffer x))))
                           target-list
                           :key #'(lambda (target)
                                    (if (listp target) (car target) target)))
        (setq buffer-only-p t)))
     ((or buffer-list-sv buffer-list)
      (setq buffer-only-p t)))

    ;; buffer/file 偱偺愗傝懼偊
    (let ((*ggrep-regexp-search* regexp-search)
          (*ggrep-case-fold-search* case-fold)
          (*ggrep-word-search* word-search)
          (*ggrep-async* async)
          (*ggrep-contents-only* contents-only)
          (*ggrep-name-only* name-only)
          (*ggrep-full-name* full-name)
          (*ggrep-encoding-name* encoding-name)
          (*ggrep-encoding-check-file* encoding-check-file)
          (*ggrep-syntax* syntax))
      (cond
       ((or target-list-sv target-list)
        (if buffer-only-p
            (ggrep1 patterns method target-list
                    :regexp-search regexp-search
                    :case-fold case-fold
                    :word-search word-search
                    :name-only name-only
                    :contents-only contents-only
                    :syntax syntax)
          (ggrep-scan-files patterns method nil nil async target-list)))
       ((or buffer-list-sv buffer-list)
        (ggrep1 patterns method buffer-list
                :regexp-search regexp-search
                :case-fold case-fold
                :word-search word-search
                :name-only name-only
                :contents-only contents-only
                :syntax syntax))
       ((or file-list-sv file-list)
        (ggrep-scan-files patterns method nil nil async file-list))
       ((or dirs-sv dirs)
        (ggrep-scan-files patterns method
                          (split-string files #\; t " ")
                          dirs async nil))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ggrep-get-setting-item (setting name &optional default)
  (let (lst)
    (if (setq lst (assoc name setting :test 'string=))
        (cadr lst)
      default)))
(defun ggrep-load-setting (setting)
  (setq *ggrep-method* (ggrep-get-setting-item setting "method"))
  (setq *ggrep-patterns* (ggrep-get-setting-item setting "patterns"))
  (setq *ggrep-select-target-method*
        (ggrep-get-setting-item setting "select-target-method"))
  (setq *ggrep-target-type* (ggrep-get-setting-item setting "target-type"))
  (setq *ggrep-directories* (ggrep-get-setting-item setting "directories"))
  (setq *ggrep-file* (ggrep-get-setting-item setting "file" "*"))
  (setq *ggrep-buffer* (ggrep-get-setting-item setting "buffer" "<僇儗儞僩僶僢僼傽>"))
  (setq *ggrep-narrow-buffer* (ggrep-get-setting-item setting "narrow-buffer" ""))
  (setq *ggrep-narrow-unit* (ggrep-get-setting-item setting "narrow-unit"))
  (setq *ggrep-file-list* (ggrep-get-setting-item setting "file-list"))
  (setq *ggrep-buffer-regexp-list* (ggrep-get-setting-item setting "buffer-regexp-list"))
  (setq *ggrep-encoding-name* (ggrep-get-setting-item setting "encoding-name"))
  (setq *ggrep-encoding-check-file*
        (ggrep-get-setting-item setting "encoding-check-file"))
  (setq *ggrep-syntax* (ggrep-get-setting-item setting "syntax" t))
  (setq *ggrep-case-fold-search*
        (ggrep-get-setting-item setting "case-fold-search"))
  (setq *ggrep-word-search* (ggrep-get-setting-item setting "word-search"))
  (setq *ggrep-regexp-search* (ggrep-get-setting-item setting "regexp-search"))
  (setq *ggrep-understand-escape-sequences*
        (ggrep-get-setting-item setting "understand-escape-sequences"))
  (setq *ggrep-async* (ggrep-get-setting-item setting "async"))
  (setq *ggrep-contents-only* (ggrep-get-setting-item setting "contents-only"))
  (setq *ggrep-name-only* (ggrep-get-setting-item setting "name-only"))
  (setq *ggrep-full-name* (ggrep-get-setting-item setting "full-name"))
  (setq *ggrep-dialog-number-of-pattern*
        (ggrep-get-setting-item setting "dialog-number-of-pattern"
                                *ggrep-dialog-number-of-pattern*))
  (setq *ggrep-dialog-number-of-dir*
        (ggrep-get-setting-item setting "dialog-number-of-dir"
                                *ggrep-dialog-number-of-dir*))
  nil)
(defun ggrep-make-setting ()
  (list (list "method" *ggrep-method*)
        (list "patterns" *ggrep-patterns*)
        (list "select-target-method" *ggrep-select-target-method*)
        (list "target-type" *ggrep-target-type*)
        (list "directories" *ggrep-directories*)
        (list "file" *ggrep-file*)
        (list "buffer" *ggrep-buffer*)
        (list "narrow-buffer" *ggrep-narrow-buffer*)
        (list "narrow-unit" *ggrep-narrow-unit*)
        (list "file-list" *ggrep-file-list*)
        (list "buffer-regexp-list" *ggrep-buffer-regexp-list*)
        (list "encoding-name" *ggrep-encoding-name*)
        (list "encoding-check-file" *ggrep-encoding-check-file*)
        (list "syntax" *ggrep-syntax*)
        (list "case-fold-search" *ggrep-case-fold-search*)
        (list "word-search" *ggrep-word-search*)
        (list "regexp-search" *ggrep-regexp-search*)
        (list "understand-escape-sequences" *ggrep-understand-escape-sequences*)
        (list "async" *ggrep-async*)
        (list "contents-only" *ggrep-contents-only*)
        (list "name-only" *ggrep-name-only*)
        (list "full-name" *ggrep-full-name*)
        (list "dialog-number-of-pattern" *ggrep-dialog-number-of-pattern*)
        (list "dialog-number-of-dir" *ggrep-dialog-number-of-dir*)))

; &A : 旕摨婜偱ggrep
; &B : 専嶕僶僢僼傽
; &C : 戝暥帤彫暥帤傪嬫暿偡傞
; &D : 僨傿儗僋僩儕悢
; &E : 惓婯昞尰
; &F : 僼傽僀儖柤
; &G : 峣崬傒扨埵: 峴
; &H : 峣崬傒扨埵: 僶僢僼傽/僼傽僀儖
; &I : 娷傓
; &J : 娷傑側偄
; &K : 巜掕愗懼
; &L : 儕僗僩庢摼
; &M : 専嶕曽朄
; &N : 峣崬傒専嶕懳徾僶僢僼傽
; &O : 僼傽僀儖柤偩偗弌椡
; &P : 僷僞乕儞悢
; &Q : 僄儞僐乕僪
; &R : 撉傒崬傒嵪傒僼傽僀儖傕巜掕僄儞僐乕僪偱
; &S : 専嶕
; &T : 愝掕
; &U : 僼儖僷僗柤偱弌椡
; &V : 僐儞僥儞僣偺傒弌椡
; &W : 扨岅扨埵偱専嶕偡傞
; &X : 僋儕傾
; &Y : 僄僗働乕僾僔乕働儞僗傪棟夝偟傠
; &Z : 揔梡

; &1-&9 : 偦傟偧傟僷僞乕儞丄僨傿儗僋僩儕傊

; &! : 
; &" :
; &# :
; &$ :
; &% :
; && :
; &' :
; &( :
; &) :
; &* : 僔儞僞僢僋僗
; &+ :
; &, :
; &- :
; &. :
; &/ :
; &: :
; &; :
; &< : 専嶕懳徾丗僼傽僀儖
; &= : 専嶕懳徾丗峣崬傒
; &> : 専嶕懳徾丗僶僢僼傽
; &? :
; &@ :
; &{ :
; &| :
; &} :
; &~ :

; TAB : 堏摦
; C-g : 僉儍儞僙儖
; ESC : 僉儍儞僙儖

(defun ggrep-dialog (&key (setting nil sv-setting) history-name history-no-load)
  (interactive)
  (let* (dialog-template
         number-of-pattern number-of-dir
         dialog-base-x dialog-x dialog-base-y dialog-y
         controls controls-initializers controls-handlers
         patenable-symbol-list pattern-symbol-list
         match-symbol-list nomatch-symbol-list
         direnable-symbol-list dir-symbol-list refdir-symbol-list
         subdir-symbol-list
         (method-symbol-list (mapcar 'cdr *ggrep-method-alist*))
         (method-display-name-list (mapcar 'car *ggrep-method-alist*))
         (grep-narrow-buffer-list
          (append '("<僇儗儞僩僶僢僼傽>")
                  (mapcar 'buffer-name (ggrep-narrow-buffer-list))))
         (char-encoding-display-name-list
          (append '("嫟捠愝掕僄儞僐乕僨傿儞僌")
                  (mapcar 'char-encoding-display-name *char-encoding-list*)))
         (char-encoding-name-list
          (append '("") (mapcar 'char-encoding-name *char-encoding-list*)))
         history
         (history-name-list (mapcar
                             #'(lambda (h)
                                 (ggrep-get-setting-item h "history-name"))
                             *ggrep-setting-history*)))
    (let (pos)
      (if (and (stringp history-name)
               (setq pos (position history-name *ggrep-setting-history*
                                   :key #'(lambda (h) (ggrep-get-setting-item h "history-name"))
                                   :test 'equal)))
          (if history-no-load
              (setq setting *last-ggrep-setting*)
            (setq setting (ggrep-get-setting-item
                           (nth pos *ggrep-setting-history*) "setting")))
        (progn
          (setq history-name nil)
          (if (and (null setting) (not sv-setting))
              (setq setting *last-ggrep-setting*)))))
    (ggrep-load-setting setting)
    (setq number-of-pattern (max *ggrep-dialog-number-of-pattern-min*
                                 (if (and (numberp *ggrep-dialog-number-of-pattern*)
                                          (integerp *ggrep-dialog-number-of-pattern*)
                                          (plusp *ggrep-dialog-number-of-pattern*))
                                     *ggrep-dialog-number-of-pattern* 0)))
    (setq number-of-dir (max *ggrep-dialog-number-of-dir-min*
                             (if (and (numberp *ggrep-dialog-number-of-dir*)
                                      (integerp *ggrep-dialog-number-of-dir*)
                                      (plusp *ggrep-dialog-number-of-dir*))
                                 *ggrep-dialog-number-of-dir* 0)))

    ;; ------------------------------------------------------------
    ;; dialog-base-x, dialog-base-y 偼僼儗乕儉偺嵗昗
    ;; ------------------------------------------------------------
    ;; 専嶕曽朄 (AND/OR)
    (setq dialog-base-x 2)
    (setq dialog-base-y 0)
    (setq dialog-x dialog-base-x)
    (setq dialog-y dialog-base-y)

    (push `(:button nil "" #x50020007
            ,dialog-x ,dialog-y 92 ,(+ 20 (* 14 number-of-pattern))) controls)
    (incf dialog-y 7)
    (push `(:static nil "専嶕曽朄(&M)" #x50020001
            ,(+ dialog-x 4) ,dialog-y 80 8) controls)
    (incf dialog-y 10)
    (push `(:combobox method nil #x50210003
            ,(+ dialog-x 4) ,dialog-y 84 48) controls)
    ;; ------------------------------------------------------------
    ;; 専嶕僷僞乕儞
    (setq dialog-base-x 96)
    (setq dialog-base-y 0)
    (setq dialog-x dialog-base-x)
    (setq dialog-y dialog-base-y)
    (push `(:button nil "" #x50020007
            ,dialog-x ,dialog-y 222 ,(+ 20 (* 14 number-of-pattern))) controls)

    (incf dialog-y 7)
    (push `(:static nil "桳岠"         #x50020001
            ,(+ dialog-x 12) ,dialog-y 16 8) controls)
    (push `(:static nil "僷僞乕儞"     #x50020001
            ,(+ dialog-x 28) ,dialog-y 140 8) controls)
    (push `(:static nil "娷傓"         #x50020001
            ,(+ dialog-x 172) ,dialog-y 14 8) controls)
    (push `(:static nil "/"            #x50020001
            ,(+ dialog-x 186) ,dialog-y 4 8) controls)
    (push `(:static nil "娷傑側偄"     #x50020001
            ,(+ dialog-x 190) ,dialog-y 26 8) controls)

    (dotimes (i number-of-pattern)
      (push (make-symbol (concat "patenable" (format nil "~D" i))) patenable-symbol-list)
      (push (make-symbol (concat "pattern" (format nil "~D" i))) pattern-symbol-list)
      (push (make-symbol (concat "match" (format nil "~D" i))) match-symbol-list)
      (push (make-symbol (concat "nomatch" (format nil "~D" i))) nomatch-symbol-list))
    (setq patenable-symbol-list (nreverse patenable-symbol-list))
    (setq pattern-symbol-list (nreverse pattern-symbol-list))
    (setq match-symbol-list (nreverse match-symbol-list))
    (setq nomatch-symbol-list (nreverse nomatch-symbol-list))

    (setq dialog-y (+ dialog-base-y 16))
    (dotimes (i number-of-pattern)
      (if (< i 9)
          (push `(:static nil ,(format nil "&~D:" (1+ i)) #x50020002
                  ,(+ dialog-x 5) ,(+ dialog-y 3) 8 8) controls)
        (push `(:static nil ,(multiple-value-bind (dec num)
                                 (floor (1+ i) 10)
                               (format nil "~D&~D:" dec num)) #x50020002
                ,(+ dialog-x 5) ,(+ dialog-y 3) 8 8) controls))

      (push `(:button ,(elt patenable-symbol-list i) nil #x50010003
              ,(+ dialog-x 16) ,dialog-y 8 14) controls)
      (push `(:combobox ,(elt pattern-symbol-list i) nil  #x50210842
              ,(+ dialog-x 28) ,dialog-y 140 96) controls)

      (push `(:button ,(elt match-symbol-list i) "(&I)" #x50000009
              ,(+ dialog-x 175) ,(+ dialog-y 2) 20 12) controls)
      (push `(:button ,(elt nomatch-symbol-list i) "(&J)" #x50000009
              ,(+ dialog-x 196) ,(+ dialog-y 2) 20 12) controls)
      (incf dialog-y 14))

    ;; ------------------------------------------------------------
    ;; 専嶕懳徾暘椶
    (setq dialog-base-x 2)
    (setq dialog-base-y (+ 20 (* 14 number-of-pattern)))
    (setq dialog-x dialog-base-x)
    (setq dialog-y dialog-base-y)
    (push `(:button nil "" #x50020007
            ,dialog-x ,dialog-y 92 ,(+ 38 (* 14 number-of-dir) 24 36)) controls)
    (incf dialog-y 7)
    (push `(:static nil "専嶕懳徾" #x50020001
            ,(+ dialog-x 4) ,dialog-y 80 8) controls)
    (incf dialog-y 10)
    (push `(:button grep-target-file "僼傽僀儖(&<)"
            ,(if (eq *ggrep-select-target-method* 'buffer-list) #x58000009 #x50000009)
            ,(+ dialog-x 8) ,dialog-y 48 10) controls)
    (incf dialog-y 14)
    (push `(:button grep-target-buffer "僶僢僼傽(&>)"
            ,(if (eq *ggrep-select-target-method* 'file-list) #x58000009 #x50000009)
            ,(+ dialog-x 8) ,dialog-y 48 10) controls)
    (incf dialog-y 14)
    (push `(:button grep-target-narrow "峣崬傒(&=)"
            ,(if (not (member *ggrep-select-target-method* '(file-list buffer-list)))
                 #x50000009 #x58000009)
            ,(+ dialog-x 8) ,dialog-y 48 10) controls)

    (incf dialog-x 4)
    (incf dialog-y 20)
    (push `(:static nil "乽僼傽僀儖乿乽峣崬傒(僼傽僀儖)乿偱偼僄儞僐乕僪巜掕偑壜擻" #x50000000
            ,dialog-x ,dialog-y 86 16) controls)
    (incf dialog-y 26)
    (push `(:static nil "乽僶僢僼傽乿乽峣崬傒(僶僢僼傽)乿偱偼僔儞僞僢僋僗巜掕偑壜擻" #x50000000
            ,dialog-x ,dialog-y 86 16) controls)


    ;; ------------------------------------------------------------
    (setq dialog-base-x 96)
;    (setq dialog-base-y (+ 20 (* 14 number-of-pattern)))
    (setq dialog-x dialog-base-x)
    (setq dialog-y dialog-base-y)

    ;; frame
    (if (or (eq *ggrep-select-target-method* 'file-list)
            (eq *ggrep-select-target-method* 'buffer-list))
        (push `(:button target-frame "" #x50020007
                ,dialog-x ,dialog-y 222 ,(+ 38 (* 14 number-of-dir) 24 36)) controls)
      (push `(:button target-frame "" #x50020007
              ,dialog-x ,dialog-y 222 ,(+ 38 (* 14 number-of-dir))) controls))

    (cond
     ;; ---
     ;; 僼傽僀儖儕僗僩巜掕
     ((eq *ggrep-select-target-method* 'file-list)
      (incf dialog-y 7)
      (push `(:static nil "僼傽僀儖儕僗僩巜掕 (僼儖僷僗)" #x50020001
              ,(+ dialog-x 12) ,dialog-y 156 8) controls)
      (incf dialog-y 9)
      (push `(:edit target-list nil #x50a110c4
              ,(+ dialog-x 8) ,dialog-y 160 ,(+ 16 (* number-of-dir 14) 24 36)) controls)
      (incf dialog-y (* number-of-dir 14))
      (push `(:button get-file-list "儕僗僩庢摼(&L)" #x50010000
              ,(+ dialog-x 172) ,(- dialog-y 12) 44 13) controls)
      (incf dialog-y 2)
      (push `(:button change-select-target-method "巜掕愗懼(&K)" #x50010000
              ,(+ dialog-x 172) ,dialog-y 44 14) controls))
     ;; ---
     ;; 僶僢僼傽儕僗僩巜掕
     ((eq *ggrep-select-target-method* 'buffer-list)
      (incf dialog-y 7)
      (push `(:static nil "僶僢僼傽儕僗僩巜掕 (惓婯昞尰)" #x50020001
              ,(+ dialog-x 12) ,dialog-y 156 8) controls)
      (incf dialog-y 9)
      (push `(:edit target-list nil #x50a110c4
              ,(+ dialog-x 8) ,dialog-y 160 ,(+ 16 (* number-of-dir 14) 24 36)) controls)
      (incf dialog-y (* number-of-dir 14))
      (push `(:button get-buffer-list "儕僗僩庢摼(&L)" #x50010000
              ,(+ dialog-x 172) ,(- dialog-y 12) 44 13) controls)
      (incf dialog-y 2)
      (push `(:button change-select-target-method "巜掕愗懼(&K)" #x50010000
              ,(+ dialog-x 172) ,dialog-y 44 14) controls))
     ;; ---
     ;; 僨傿儗僋僩儕巜掕
     (t
      (dotimes (i number-of-dir)
        (push (make-symbol (concat "direnable" (format nil "~D" i))) direnable-symbol-list)
        (push (make-symbol (concat "dir" (format nil "~D" i))) dir-symbol-list)
        (push (make-symbol (concat "refdir" (format nil "~D" i))) refdir-symbol-list)
        (push (make-symbol (concat "subdir" (format nil "~D" i))) subdir-symbol-list))
      (setq direnable-symbol-list (nreverse direnable-symbol-list))
      (setq dir-symbol-list (nreverse dir-symbol-list))
      (setq refdir-symbol-list (nreverse refdir-symbol-list))
      (setq subdir-symbol-list (nreverse subdir-symbol-list))

      (incf dialog-y 7)
      (push `(:static nil "桳岠" #x50020001
              ,(+ dialog-x 12) ,dialog-y 16 8) controls)
      (push `(:static nil "僨傿儗僋僩儕" #x50020001
              ,(+ dialog-x 28) ,dialog-y 140 8) controls)
      (push `(:static nil "僒僽僨傿儗僋僩儕" #x50020001
              ,(+ dialog-x 178) ,dialog-y 40 8) controls)

      (incf dialog-y 9)
      (dotimes (i number-of-dir)
        (if (< i 9)
            (push `(:static nil ,(format nil "&~D:" (1+ i)) #x50020002
                    ,(+ dialog-x 5) ,(+ dialog-y 3) 8 8) controls)
          (push `(:static nil ,(multiple-value-bind (dec num)
                                   (floor (1+ i) 10)
                                 (format nil "~D&~D:" dec num)) #x50020002
                  ,(+ dialog-x 5) ,(+ dialog-y 3) 8 8) controls))

        (push `(:button ,(elt direnable-symbol-list i) nil #x50010003
                ,(+ dialog-x 16) ,dialog-y 8 14) controls)
        (push `(:combobox ,(elt dir-symbol-list i) nil  #x50210842
                ,(+ dialog-x 28) ,dialog-y 140 96) controls)
        (push `(:button ,(elt refdir-symbol-list i) "嶲徠..." #x50010000
                ,(+ dialog-x 172) ,dialog-y 22 14) controls)
        (push `(:button ,(elt subdir-symbol-list i) nil #x50010003
                ,(+ dialog-x 198) ,dialog-y 8 14) controls)
        (incf dialog-y 14))

      (incf dialog-y 2)
      (push `(:static nil "僼傽僀儖柤(&F):" #x50020000
              ,(+ dialog-x 7) ,(+ dialog-y 2) 38 8) controls)
      (push `(:combobox file nil  #x50210842
              ,(+ dialog-x 44) ,dialog-y 124 96) controls)
      (push `(:button change-select-target-method "巜掕愗懼(&K)" #x50010000
              ,(+ dialog-x 172) ,dialog-y 44 14) controls)))

    ;; ------------------------------------------------------------
    (if (or (eq *ggrep-select-target-method* 'file-list)
            (eq *ggrep-select-target-method* 'buffer-list))
        (progn
          (incf dialog-base-y (+ 38 (* 14 number-of-dir)))
          (incf dialog-base-y 24))
      (progn
        ;; ------------------------------------------------------------
        ;; 僶僢僼傽専嶕
        (setq dialog-base-x 96)
        (incf dialog-base-y (+ 38 (* 14 number-of-dir)))
        (setq dialog-x dialog-base-x)
        (setq dialog-y dialog-base-y)
        (push `(:button nil "" #x50020007 ,dialog-x ,dialog-y 222 24) controls)
        (incf dialog-y 7)
        (push `(:static grep-buffer-label "専嶕僶僢僼傽(&B):" #x50020000
                ,(+ dialog-x 7) ,(+ dialog-y 2) 80 8) controls)
        (push `(:combobox grep-target-buffer-list nil #x50210003
                ,(+ dialog-x 56) ,dialog-y 112 96) controls)

        ;; ------------------------------------------------------------
        ;; 峣崬傒専嶕
        (setq dialog-base-x 96)
        (incf dialog-base-y 24)
        (setq dialog-x dialog-base-x)
        (setq dialog-y dialog-base-y)
        (push `(:button nil "" #x50020007 ,dialog-x ,dialog-y 222 36) controls)
        (incf dialog-y 7)
        (push `(:static grep-buffer-narrow-list-label "峣崬傒僶僢僼傽(&N):" #x50020000
                ,(+ dialog-x 7) ,(+ dialog-y 2) 80 8) controls)
        (push `(:combobox grep-narrow-buffer-list nil
                ,(if (plusp (length grep-narrow-buffer-list)) #x50210003 #x58210003)
                ,(+ dialog-x 56) ,dialog-y 112 64) controls)
        (incf dialog-y 14)
        (push `(:static grep-buffer-narrow-unit-label "峣崬傒尦:" #x50020000
                ,(+ dialog-x 7) ,(+ dialog-y 2) 60 8) controls)
        (push `(:button grep-narrow-unit-line "儅僢僠峴偺傒(&G)" #x50000009
                ,(+ dialog-x 56) ,(+ dialog-y 2) 60 10) controls)
        (push `(:button grep-narrow-unit-buffer "儅僢僠偟偨僶僢僼傽/僼傽僀儖慡懱(&H)" #x50000009
                ,(+ dialog-x 116) ,(+ dialog-y 2) 100 10) controls)))

    ;; ------------------------------------------------------------
    (setq dialog-base-x 96)
    (setq dialog-base-y (+ 20 (* 14 number-of-pattern) ;僷僞乕儞
                           38 (* 14 number-of-dir)     ;僨傿儗僋僩儕
                           24                          ;僶僢僼傽
                           36))                        ;峣崬傒
    (setq dialog-x dialog-base-x)
    (setq dialog-y dialog-base-y)
    (push `(:button nil "" #x50020007 ,dialog-x ,dialog-y 222 36) controls)
    (incf dialog-y 7)
    (push `(:static encoding-label "僄儞僐乕僪(&Q):" #x50020000
            ,(+ dialog-x 7) ,(+ dialog-y 2) 38 8) controls)
    (push `(:combobox encoding nil #x50210003
            ,(+ dialog-x 44) ,dialog-y 124 96) controls)
    (push `(:button encoding-check-file "僶僢僼傽撉傒崬傒嵪傒僼傽僀儖傕巜掕僄儞僐乕僪偱僼傽僀儖偐傜専嶕(&R)"
            #x50010003 ,(+ dialog-x 16) ,(+ dialog-y 16) 190 10) controls)

    ;; ------------------------------------------------------------
    (setq dialog-base-x 96)
    (incf dialog-base-y 36)
    (setq dialog-x dialog-base-x)
    (setq dialog-y dialog-base-y)
    (push `(:button nil "" #x50020007 ,dialog-x ,dialog-y 222 22) controls)
    (incf dialog-y 7)
    (push `(:static syntax-label "僔儞僞僢僋僗(&*):" #x50020000
            ,(+ dialog-x 7) ,(+ dialog-y 2) 42 8) controls)
    (incf dialog-y 1)
    (push `(:button syntax-all "慡偰" #x50010003
            ,(+ dialog-x 48) ,dialog-y 34 10) controls)
    (push `(:button syntax-string "暥帤楍" #x50010003
            ,(+ dialog-x 79) ,dialog-y 34 10) controls)
    (push `(:button syntax-comment "僐儊儞僩" #x50010003
            ,(+ dialog-x 114) ,dialog-y 34 10) controls)
    (push `(:button syntax-tag "僞僌" #x50010003
            ,(+ dialog-x 149) ,dialog-y 34 10) controls)
    (push `(:button syntax-nil "枹暘椶" #x50010003
            ,(+ dialog-x 184) ,dialog-y 34 10) controls)

    ;; ------------------------------------------------------------
    (incf dialog-base-y 22)
    (setq dialog-y dialog-base-y)
    (push `(:button case-fold "戝暥帤彫暥帤傪嬫暿偡傞(&C)" #x50010006
            31 ,(incf dialog-y 7) 113 10) controls)
    (push `(:button word "扨岅扨埵偱専嶕偡傞(&W)" #x50010003
            31 ,(incf dialog-y 13)  97 10) controls)
    (push `(:button regexp "惓婯昞尰(&E)" #x50010003
            31 ,(incf dialog-y 13)  62 10) controls)
    (push `(:button escseq "僄僗働乕僾僔乕働儞僗傪棟夝偟傠(&Y)" #x50010003
            31 ,(incf dialog-y 13) 113 10) controls)
    (push `(:button async "旕摨婜偱ggrep(&A)" #x50010003
            31 ,(incf dialog-y 13) 103 10) controls)
    (push `(:button contents-only "僐儞僥儞僣偺傒弌椡(&V)" #x50010003
            31 ,(incf dialog-y 13)  84 10) controls)
    (push `(:button name "僶僢僼傽/僼傽僀儖柤偩偗弌椡(&O)" #x50010003
            31 ,(incf dialog-y 13)  94 10) controls)
    (push `(:button full-name "僼儖僷僗柤偱弌椡(&U)" #x50010003
            31 ,(incf dialog-y 13)  84 10) controls)

    (setq dialog-y (+ dialog-base-y 14))
    (push `(:static pat-resize-label "僷僞乕儞悢(&P):"   #x50020000
            146 ,(+ dialog-y 3) 50  8) controls)
    (push `(:edit pat-resize-num nil     #x50812086
            194 ,dialog-y 36 14) controls)
    (push `(:spin pat-resize-numspin nil #x500000b6
            230 ,dialog-y 10 14) controls)
    (incf dialog-y 17)
    (push `(:static dir-resize-label "僨傿儗僋僩儕悢(&D):" #x50020000
            146 ,(+ dialog-y 3) 50  8) controls)
    (push `(:edit dir-resize-num nil     #x50812086
            194 ,dialog-y 36 14) controls)
    (push `(:spin dir-resize-numspin nil #x500000b6
            230 ,dialog-y 10 14) controls)
    (incf dialog-y 16)
    (push `(:static dir-resize-comment "(儕僗僩巜掕椞堟崅偝)" #x50020000
            172 ,dialog-y 58 8) controls)

    (setq dialog-y dialog-base-y)
    (push `(:button IDOK "専嶕(&S)"  #x50010001
            246 ,(incf dialog-y 11) 50 14) controls)
    (push `(:button IDCANCEL "僉儍儞僙儖" #x50010000
            246 ,(incf dialog-y 17) 50 14) controls)
    (push `(:button apply "揔梡(&Z)" #x50010000
            246 ,(incf dialog-y 17) 50 14) controls)
    (push `(:button clear "僋儕傾(&X)" #x50010000
            246 ,(incf dialog-y 17) 50 14) controls)

    (setq dialog-y (+ dialog-base-y 96))
    (push `(:static history-label "愝掕(&T):" #x50020001
            120 ,(+ dialog-y 2) 30 8) controls)
    (push `(:combobox history nil #x50210842
            150 ,dialog-y 80 80) controls)
    (push `(:button history-save "曐懚"  #x50010000
            234 ,dialog-y 24 14) controls)
    (push `(:button history-load "撉崬"  #x50010000
            260 ,dialog-y 24 14) controls)
    (push `(:button history-del "嶍彍"  #x50010000
            286 ,dialog-y 24 14) controls)

    (setq dialog-base-y (+ dialog-y 18))

    (setq controls (nreverse controls))
    
    ;; controls-initializers 偺惗惉
    (push `(method . ,method-display-name-list)
          controls-initializers)
    (push `(method . ,(or (position *ggrep-method* method-symbol-list) 0)) controls-initializers)
    (push `(pat-resize-num . ,(format nil "~D" number-of-pattern))
          controls-initializers)
    (dotimes (i number-of-pattern)
      (push `(,(elt patenable-symbol-list i) .
              ,(ggrep-get-setting-item (nth i *ggrep-patterns*) "enable" t))
            controls-initializers)
      (push `(,(elt match-symbol-list i) .
              ,(ggrep-get-setting-item (nth i *ggrep-patterns*) "match" t))
            controls-initializers)
      (push `(,(elt nomatch-symbol-list i) .
              ,(not (ggrep-get-setting-item (nth i *ggrep-patterns*) "match" t)))
            controls-initializers)
      (push `(,(elt pattern-symbol-list i) .
              ,(ggrep-get-setting-item (nth i *ggrep-patterns*) "pattern" ""))
            controls-initializers)
      (push `(,(elt pattern-symbol-list i) . ,*minibuffer-search-string-history*)
            controls-initializers))

    (cond ((eq *ggrep-select-target-method* 'file-list)
           (push '(grep-target-file . t) controls-initializers)
           (push '(grep-target-buffer . nil) controls-initializers)
           (push '(grep-target-narrow . nil) controls-initializers))
          ((eq *ggrep-select-target-method* 'buffer-list)
           (push '(grep-target-file . nil) controls-initializers)
           (push '(grep-target-buffer . t) controls-initializers)
           (push '(grep-target-narrow . nil) controls-initializers))
          ((eq *ggrep-target-type* :file)
           (push '(grep-target-file . t) controls-initializers)
           (push '(grep-target-buffer . nil) controls-initializers)
           (push '(grep-target-narrow . nil) controls-initializers))
          ((eq *ggrep-target-type* :buffer)
           (push '(grep-target-file . nil) controls-initializers)
           (push '(grep-target-buffer . t) controls-initializers)
           (push '(grep-target-narrow . nil) controls-initializers))
          ((eq *ggrep-target-type* :narrow)
           (push '(grep-target-file . nil) controls-initializers)
           (push '(grep-target-buffer . nil) controls-initializers)
           (push '(grep-target-narrow . t) controls-initializers))
          (t
           (push '(grep-target-file . t) controls-initializers)
           (push '(grep-target-buffer . nil) controls-initializers)
           (push '(grep-target-narrow . nil) controls-initializers)))

    (push `(dir-resize-num . ,(format nil "~D" number-of-dir))
          controls-initializers)
    (dotimes (i number-of-dir)
      (push `(,(elt direnable-symbol-list i) .
              ,(ggrep-get-setting-item (nth i *ggrep-directories*) "enable" t))
            controls-initializers)
      (push `(,(elt subdir-symbol-list i) .
              ,(ggrep-get-setting-item (nth i *ggrep-directories*) "subdir"
                                       *ggrep-subdir-default*))
            controls-initializers)
      (push `(,(elt dir-symbol-list i) .
              ,(ggrep-get-setting-item (nth i *ggrep-directories*) "directory" ""))
            controls-initializers)
      (if (= i 0)
          (push `(,(elt dir-symbol-list i) .
                  ,(append (list "<僇儗儞僩僨傿儗僋僩儕>") *grep-directory-history*)) controls-initializers)
        (push `(,(elt dir-symbol-list i) . ,*grep-directory-history*) controls-initializers)))
    (push `(file . ,*ggrep-file*) controls-initializers)
    (push `(file . ,*grep-file-history*) controls-initializers)

    (let ((buffer-list (append (list "<僇儗儞僩僶僢僼傽>" "<慡昞帵僶僢僼傽>")
                               (delete "^ \\*Minibuf[0-9]+\\*$"
                                       (mapcar 'buffer-name (buffer-list))
                                       :test 'string-match))))
      (push `(grep-target-buffer-list . ,buffer-list) controls-initializers)
      (push `(grep-target-buffer-list
              . ,(or (position *ggrep-buffer* buffer-list :test 'string=) 0)) controls-initializers))

    (let ((escape-char-alist
           '(("\n" . "\\\\n") ("\r" . "\\\\r") ("\t" . "\\\\t") ("\f" . "\\\\f"))))
      (flet ((encode-escape-sequence (string)
               (cond
                ((stringp string)
                 (dolist (ec escape-char-alist)
                   (setq string (substitute-string string (car ec) (cdr ec))))
                 string)
                (t nil))))
        (cond
         ((eq *ggrep-select-target-method* 'file-list)
          (push `(target-list . ,(format nil "~{~A\r\n~}"
                                         (mapcar #'encode-escape-sequence *ggrep-file-list*)))
                controls-initializers))
         ((eq *ggrep-select-target-method* 'buffer-list)
          (push `(target-list . ,(format nil "~{~A\r\n~}"
                                         (mapcar #'encode-escape-sequence *ggrep-buffer-regexp-list*)))
                controls-initializers)))))

    (push `(grep-narrow-buffer-list . ,grep-narrow-buffer-list) controls-initializers)
    (push `(grep-narrow-buffer-list . ,(or (position *ggrep-narrow-buffer*
                                              grep-narrow-buffer-list
                                              :test 'string=) 0)) controls-initializers)
    (cond ((eq *ggrep-narrow-unit* :buffer)
           (push '(grep-narrow-unit-buffer . t) controls-initializers)
           (push '(grep-narrow-unit-line . nil) controls-initializers))
          (t
           (push '(grep-narrow-unit-buffer . nil) controls-initializers)
           (push '(grep-narrow-unit-line . t) controls-initializers)))
    (push `(syntax-all . ,(eq *ggrep-syntax* t)) controls-initializers)
    (push `(syntax-string . ,(or (eq *ggrep-syntax* t) (member :string *ggrep-syntax*)))
          controls-initializers)
    (push `(syntax-comment . ,(or (eq *ggrep-syntax* t) (member :comment *ggrep-syntax*)))
          controls-initializers)
    (push `(syntax-tag . ,(or (eq *ggrep-syntax* t) (member :tag *ggrep-syntax*)))
          controls-initializers)
    (push `(syntax-nil . ,(or (eq *ggrep-syntax* t) (member nil *ggrep-syntax*)))
          controls-initializers)
    (push `(encoding . ,char-encoding-display-name-list) controls-initializers)
    (push `(encoding . ,(or (position *ggrep-encoding-name*
                                      char-encoding-name-list
                                      :test 'string=) 0)) controls-initializers)
    (push (cons 'encoding-check-file *ggrep-encoding-check-file*)
          controls-initializers)
    (push (cons 'case-fold (cfs2dialog *ggrep-case-fold-search*))
          controls-initializers)
    (push (cons 'word *ggrep-word-search*) controls-initializers)
    (push (cons 'regexp *ggrep-regexp-search*) controls-initializers)
    (push (cons 'escseq *ggrep-understand-escape-sequences*) controls-initializers)
    (push (cons 'async *ggrep-async*) controls-initializers)
    (push (cons 'contents-only *ggrep-contents-only*) controls-initializers)
    (push (cons 'name *ggrep-name-only*) controls-initializers)
    (push (cons 'full-name *ggrep-full-name*) controls-initializers)

    (push (cons 'history history-name) controls-initializers)
    (push (cons 'history history-name-list) controls-initializers)

    (setq controls-initializers (nreverse controls-initializers))

    ;; controls-handlers 偺惗惉
    (push `(method :index t) controls-handlers)
    (dotimes (i number-of-dir)
      (push `(,(elt refdir-symbol-list i) :related ,(elt dir-symbol-list i)
              :directory-name-dialog (:title "嶲徠")) controls-handlers))

    ;; ----------------------------------------
    (let ((target-file-symbols
           (append direnable-symbol-list dir-symbol-list refdir-symbol-list
                   subdir-symbol-list '(file)))
          (target-buffer-symbols '(grep-target-buffer-list))
          (target-narrow-symbols '(grep-narrow-buffer-list grep-narrow-unit-line grep-narrow-unit-buffer)))
      (push `(grep-target-file :enable ,target-file-symbols
                               :disable ,(append target-buffer-symbols target-narrow-symbols))
            controls-handlers)
      (push `(grep-target-buffer :enable ,target-buffer-symbols
                               :disable ,(append target-file-symbols target-narrow-symbols))
            controls-handlers)
      (push `(grep-target-narrow :enable ,target-narrow-symbols
                                 :disable ,(append target-file-symbols target-buffer-symbols))
            controls-handlers))
    ;; ----------------------------------------
    
    (push '(grep-narrow-buffer-list :index t) controls-handlers)
    (push '(syntax-all :disable (syntax-string syntax-comment syntax-tag syntax-nil))
          controls-handlers)
    (push '(encoding :index t) controls-handlers)
    (push `(pat-resize-num :min ,*ggrep-dialog-number-of-pattern-min*
                           :max 99 :range-error
                           ,(format nil "~D 埲忋 99 埲壓傪巜掕偟偰偔偩偝偄"
                                    *ggrep-dialog-number-of-pattern-min*)
           :type integer :type-error "悢抣傪擖椡偟偰偔偩偝偄") controls-handlers)
    (push `(pat-resize-numspin :min ,*ggrep-dialog-number-of-pattern-min*
                               :max 99) controls-handlers)
    (push `(dir-resize-num :min ,*ggrep-dialog-number-of-dir-min*
                           :max 99 :range-error
                           ,(format nil "~D 埲忋 99 埲壓傪巜掕偟偰偔偩偝偄"
                                    *ggrep-dialog-number-of-dir-min*)
            :type integer :type-error "悢抣傪擖椡偟偰偔偩偝偄") controls-handlers)
    (push `(dir-resize-numspin :min ,*ggrep-dialog-number-of-dir-min*
                               :max 99) controls-handlers)
    (push '(word :disable (regexp)) controls-handlers)
    (push '(contents-only :disable (name full-name)) controls-handlers)

    (setq controls-handlers (nreverse controls-handlers))

    ;;
    (setq dialog-template
          `(dialog 0 0 320 ,dialog-base-y
                   (:caption ,(if (stringp history-name)
                                  (concat "GGrep - [" history-name "]") "GGrep"))
                   (:font 9 "MS UI Gothic")
                   (:control
                    ,@controls)))
    (multiple-value-bind (result data)
        (dialog-box dialog-template
                    controls-initializers
                    controls-handlers)
      (when result
        (let (patterns)
          (si:*activate-toplevel)
          ;; *ggrep-method* 偺庢摼
          (setq *ggrep-method* (nth (or (cdr (assoc 'method data)) 0) method-symbol-list))
;          dialog 偱偺愝掕曄峏傪偳偙傑偱 minibuffer 偱偺幚峴帪偵斀塮偝偣傞偐丅
;          (setq *last-ggrep-method* *ggrep-method*)

          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
          ;; 仭僟僀傾儘僌偐傜偺忣曬偺庢摼
          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

          ;; *ggrep-patterns* 偺庢摼
          (setq *ggrep-patterns* nil)
          (dotimes (i number-of-pattern)
            (push
             (list (list (copy-string "enable") (cdr (assoc (elt patenable-symbol-list i) data)))
                   (list (copy-string "pattern") (cdr (assoc (elt pattern-symbol-list i) data)))
                   (list (copy-string "match") (cdr (assoc (elt match-symbol-list i) data))))
             *ggrep-patterns*))
          (dolist (p *ggrep-patterns*)
            (if (string/= (ggrep-get-setting-item p "pattern") "")
                (add-history (ggrep-get-setting-item p "pattern")
                             '*minibuffer-search-string-history*)))
          (setq *ggrep-patterns* (nreverse *ggrep-patterns*))

          ;; *ggrep-target-type* 偺庢摼
          (unless (or (eq *ggrep-select-target-method* 'file-list)
                      (eq *ggrep-select-target-method* 'buffer-list))
            (cond ((cdr (assoc 'grep-target-file data))
                   (setq *ggrep-target-type* :file))
                  ((cdr (assoc 'grep-target-buffer data))
                   (setq *ggrep-target-type* :buffer))
                  ((cdr (assoc 'grep-target-narrow data))
                   (setq *ggrep-target-type* :narrow))
                  (t
                   (setq *ggrep-target-type* :file))))

          ;; *ggrep-select-target-method* 枅偵抣傪庢摼
          (cond
           ;; *ggrep-file-list* 庢摼
           ((eq *ggrep-select-target-method* 'file-list)
            (setq *ggrep-file-list*
                  (mapcar #'(lambda (str)
                              (decode-escape-sequence str nil))
                          (split-string (substitute-string (cdr (assoc 'target-list data))
                                                           "\r\n" "\n") #\LFD))))
           ;; *ggrep-buffer-regexp-list* 庢摼
           ((eq *ggrep-select-target-method* 'buffer-list)
            (setq *ggrep-buffer-regexp-list*
                  (mapcar #'(lambda (str)
                              (decode-escape-sequence str t))
                          (split-string (substitute-string (cdr (assoc 'target-list data))
                                                           "\r\n" "\n") #\LFD))))
           ;;
           (t
            (cond
             ((eq *ggrep-target-type* :file)
              (setq *ggrep-directories* nil)
              (dotimes (i number-of-dir)
                (push
                 (list (list (copy-string "enable") (cdr (assoc (elt direnable-symbol-list i) data)))
                       (list (copy-string "directory") (cdr (assoc (elt dir-symbol-list i) data)))
                       (list (copy-string "subdir") (cdr (assoc (elt subdir-symbol-list i) data))))
                 *ggrep-directories*))
              (dolist (d *ggrep-directories*)
                (if (and (string/= (ggrep-get-setting-item d "directory") "")
                         (string-match (ggrep-get-setting-item d "directory") "[<>]"))
                    (add-history (ggrep-get-setting-item d "directory")
                                 '*grep-directory-history*)))
              (setq *ggrep-directories* (nreverse *ggrep-directories*))
              (setq *ggrep-file* (cdr (assoc 'file data)))
              (add-history *ggrep-file* '*grep-file-history*))
             ;;
             ((eq *ggrep-target-type* :buffer)
              (setq *ggrep-buffer* (cdr (assoc 'grep-target-buffer-list data))))
             ;; 峣崬傒巜掕
             ((eq *ggrep-target-type* :narrow)
              (setq *ggrep-narrow-buffer*
                    (elt grep-narrow-buffer-list (cdr (assoc 'grep-narrow-buffer-list data))))
              (if (cdr (assoc 'grep-narrow-unit-buffer data))
                  (setq *ggrep-narrow-unit* :buffer)
                (setq *ggrep-narrow-unit* :line))))))

          (cond
           ;; 僼傽僀儖儕僗僩偺庢摼
           ((eq result 'get-file-list)
            (let (lst)
              (dolist (x (mapcar 'get-buffer-file-name (buffer-list)))
                (when x
                  (push x lst)))
              (setq *ggrep-file-list* (nreverse lst))))
           ;; 僶僢僼傽儕僗僩偺庢摼
           ((eq result 'get-buffer-list)
            (setq *ggrep-buffer-regexp-list*
                  (mapcar #'(lambda (buffer)
                              (concat "^" (regexp-quote (buffer-name buffer)) "$"))
                          (buffer-list))))
           ;; 専嶕懳徾巜掕夋柺偺曄峏 (昗弨->僼傽僀儖儕僗僩->僶僢僼傽儕僗僩->昗弨)
           ((eq result 'change-select-target-method)
            (cond
             ((eq *ggrep-select-target-method* 'file-list)
              (setq *ggrep-select-target-method* 'buffer-list))
             ((eq *ggrep-select-target-method* 'buffer-list)
              (setq *ggrep-select-target-method* nil))
             (t
              (setq *ggrep-select-target-method* 'file-list)))))

          ;; syntax 巜掕
          (if (cdr (assoc 'syntax-all data))
              (setq *ggrep-syntax* t)
            (progn
              (setq *ggrep-syntax* nil)
              (when (cdr (assoc 'syntax-string data)) (push :string *ggrep-syntax*))
              (when (cdr (assoc 'syntax-comment data)) (push :comment *ggrep-syntax*))
              (when (cdr (assoc 'syntax-tag data)) (push :tag *ggrep-syntax*))
              (when (cdr (assoc 'syntax-nil data)) (push nil *ggrep-syntax*))))

          ;; 僄儞僐乕僪巜掕
          (setq *ggrep-encoding-name* (elt char-encoding-name-list
                                           (cdr (assoc 'encoding data))))
          (if (string= "" *ggrep-encoding-name*)
              (setq *ggrep-encoding-name* nil))
          (setq *ggrep-encoding-check-file* (cdr (assoc 'encoding-check-file data)))

          ;; 奺庬僆僾僔儑儞
          (setq *ggrep-case-fold-search* (dialog2cfs (cdr (assoc 'case-fold data))))
          (setq *ggrep-word-search* (cdr (assoc 'word data)))
          (setq *ggrep-regexp-search* (cdr (assoc 'regexp data)))
          (setq *ggrep-understand-escape-sequences* (cdr (assoc 'escseq data)))
          (setq *ggrep-async* (cdr (assoc 'async data)))
          (setq *ggrep-name-only* (cdr (assoc 'name data)))
          (setq *ggrep-full-name* (cdr (assoc 'full-name data)))
          (setq *ggrep-contents-only* (cdr (assoc 'contents-only data)))

          ;; 擖椡崁栚悢挷惍
          (setq *ggrep-dialog-number-of-pattern* (cdr (assoc 'pat-resize-num data)))
          (setq *ggrep-dialog-number-of-dir* (cdr (assoc 'dir-resize-num data)))

          ;; 愝掕忣曬偺曐懚
          (setq *last-ggrep-setting* (ggrep-make-setting))

          ;; 愝掕柤娭楢偺儃僞儞墴壓帪偺傒 history-name 傪曄峏
          (when (member result '(history-del history-save history-load))
            (setq history-name (cdr (assoc 'history data))))

          (setq patterns (ggrep-patterns-normalization
                          *ggrep-patterns*
                          :regexp-search *ggrep-regexp-search*
                          :understand-escape-sequences *ggrep-understand-escape-sequences*))

          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          ;; 仭嵟廔揑偵墴偟偨儃僞儞偵懳偡傞摦嶌
          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

          (cond
           ;; 僋儕傾
           ((eq result 'clear)
            (ggrep-dialog :setting nil))
           ;; 揔梡
           ((eq result 'apply)
            (ggrep-dialog :history-name history-name :history-no-load t))
           ;; 僼傽僀儖儕僗僩愗懼
           ((eq result 'change-select-target-method)
            (ggrep-dialog :history-name history-name :history-no-load t))
           ;; 僼傽僀儖儕僗僩庢摼
           ((eq result 'get-file-list)
            (ggrep-dialog :history-name history-name :history-no-load t))
           ;; 僶僢僼傽儕僗僩庢摼
           ((eq result 'get-buffer-list)
            (ggrep-dialog :history-name history-name :history-no-load t))
           ;; 専嶕
           ((eq result 'IDOK)
            (cond
             ;; 僼傽僀儖儕僗僩巜掕専嶕
             ((eq *ggrep-select-target-method* 'file-list)
              (ggrep-scan-files patterns *ggrep-method* nil nil *ggrep-async* *ggrep-file-list*))
             ;; 僶僢僼傽儕僗僩巜掕専嶕
             ((eq *ggrep-select-target-method* 'buffer-list)
              (let (buffer-list)
                (dolist (buffer (buffer-list))
                  (dolist (regexp *ggrep-buffer-regexp-list*)
                    (when (string-match regexp (buffer-name buffer))
                      (push buffer buffer-list)
                      (return))))
                (ggrep1 patterns *ggrep-method* (nreverse buffer-list)
                        :case-fold *ggrep-case-fold-search*
                        :word-search *ggrep-word-search*
                        :name-only *ggrep-name-only*
                        :contents-only *ggrep-contents-only*
                        :syntax *ggrep-syntax*)))
             ;; 僶僢僼傽専嶕
             ((eq *ggrep-target-type* :buffer)
              (cond
               ;; 僇儗儞僩僶僢僼傽専嶕
               ((string= *ggrep-buffer* "<僇儗儞僩僶僢僼傽>")
                (ggrep1 patterns *ggrep-method* t
                        :case-fold *ggrep-case-fold-search*
                        :word-search *ggrep-word-search*
                        :name-only *ggrep-name-only*
                        :contents-only *ggrep-contents-only*
                        :syntax *ggrep-syntax*))
               ;; 慡昞帵僶僢僼傽専嶕
               ((string= *ggrep-buffer* "<慡昞帵僶僢僼傽>")
                (ggrep1 patterns *ggrep-method* nil
                        :case-fold *ggrep-case-fold-search*
                        :word-search *ggrep-word-search*
                        :name-only *ggrep-name-only*
                        :contents-only *ggrep-contents-only*
                        :syntax *ggrep-syntax*))
               (t
                (ggrep1 patterns *ggrep-method* (list *ggrep-buffer*)
                        :case-fold *ggrep-case-fold-search*
                        :word-search *ggrep-word-search*
                        :name-only *ggrep-name-only*
                        :contents-only *ggrep-contents-only*
                        :syntax *ggrep-syntax*))))
             ;; 僨傿儗僋僩儕巜掕専嶕
             ((eq *ggrep-target-type* :file)
              (ggrep-scan-files patterns *ggrep-method*
                                (split-string *ggrep-file* #\; t " ")
                                *ggrep-directories* *ggrep-async*))
             ;; 峣崬傒専嶕
             ((eq *ggrep-target-type* :narrow)
              (let ((target-list
                     (ggrep-get-target-list (if (string= *ggrep-narrow-buffer* "<僇儗儞僩僶僢僼傽>")
                                                (selected-buffer)
                                              (find-buffer *ggrep-narrow-buffer*))
                                            *ggrep-narrow-unit*)))
                ;; 愭摢偑 buffer 側傜偽慡偰 buffer 偲敾抐
                (if (or (bufferp (car target-list))
                        (and (listp (car target-list))
                             (bufferp (caar target-list))))
                    (ggrep1 patterns *ggrep-method* target-list
                            :case-fold *ggrep-case-fold-search*
                            :word-search *ggrep-word-search*
                            :name-only *ggrep-name-only*
                            :contents-only *ggrep-contents-only*
                            :syntax *ggrep-syntax*)
                  (ggrep-scan-files patterns *ggrep-method* nil nil *ggrep-async* target-list))))))
           ;; 嶍彍
           ((eq result 'history-del)
            (let (pos)
              (if (setq pos
                        (position history-name *ggrep-setting-history*
                                  :key #'(lambda (h) (ggrep-get-setting-item h "history-name"))
                                  :test 'equal))
                  (setq *ggrep-setting-history*
                        (append (subseq *ggrep-setting-history* 0 pos)
                                (subseq *ggrep-setting-history* (1+ pos))))))
            (ggrep-dialog))
           ;; 曐懚
           ((eq result 'history-save)
            (let (pos)
              (when (string-match "^[ \t]*$" history-name)
                (setq history-name (format-date-string "%Y/%m/%d %H:%M:%S")))
              (if (setq pos
                        (position history-name *ggrep-setting-history*
                                  :key #'(lambda (h) (ggrep-get-setting-item h "history-name"))
                                  :test 'equal))
                  (setq *ggrep-setting-history*
                        (append (subseq *ggrep-setting-history* 0 pos)
                                (subseq *ggrep-setting-history* (1+ pos)))))
              (push (list (list "history-name" history-name)
                          (list "setting" *last-ggrep-setting*))
                    *ggrep-setting-history*))
            (ggrep-dialog :history-name history-name))
           ;; 撉崬
           ((eq result 'history-load)
            (let (pos history)
              (if (setq pos
                        (position history-name *ggrep-setting-history*
                                  :key #'(lambda (h) (ggrep-get-setting-item h "history-name"))
                                  :test 'equal))
                  (progn
                    (setq history (nth pos *ggrep-setting-history*))
                    (setq *last-ggrep-setting* (ggrep-get-setting-item history "setting"))
                    (setq *ggrep-setting-history*
                          (append (subseq *ggrep-setting-history* 0 pos)
                                  (subseq *ggrep-setting-history* (1+ pos))))
                    (push history *ggrep-setting-history*)
                    (ggrep-dialog :history-name history-name))
                (ggrep-dialog :setting nil)))))
          t)))))

;; menu
(defun ggrep-insert-menu-items (&key menu pre-tag position head-sep tail-sep)
  (if (and (not (menup menu)) (menup *app-menu*))
      (setq menu (get-menu *app-menu* 'ed::search)))
  (when (menup menu)
    (ggrep-delete-menu menu)
    (unless (or pre-tag position)
      (setq pre-tag 'ed::grep-dialog))
    (when (and pre-tag
               (setq position (get-menu-position menu pre-tag)))
      (incf position))
    (unless (and (numberp position) (integerp position) (not (minusp position))
                 (get-menu menu position t))
      (setq position -1)
      (while (get-menu menu (incf position) t)))
    (decf position)
    (if (and head-sep
             (not (minusp position))
             (get-menu menu position t))
        (insert-menu-separator menu (incf position) 'ggrep-sep))
    (insert-menu-item menu (incf position) 'ggrep-dialog
                      "GGrep(&H)..."
                      'ggrep-dialog)
    (if (and tail-sep
             (get-menu menu (incf position) t))
        (insert-menu-separator menu position 'ggrep-sep))))
(defun ggrep-delete-menu (&optional menu)
  (if (and (not (menup menu)) (menup *app-menu*))
      (setq menu (get-menu *app-menu* 'ed::search)))
  (when (menup menu)
    (while (delete-menu menu 'ggrep-dialog))
    (while (delete-menu menu 'ggrep-sep))))

;; tool-bar
(defun ggrep-tool-bar ()
  (create-tool-bar
   'ggrep-tool-bar
   (merge-pathnames "toolbar-ggrep.bmp" (etc-path))
   '(("ggrep" 0 ggrep-dialog))))
(define-command-bar 'ggrep-tool-bar "GGrep(&G)")

;; uninstall
(defun ggrep-uninstall ()
  (let ((history-variables
         '(*last-ggrep-regexp-list*
           *last-fggrep-pattern-list*
           *last-ggrep-method*
           *last-ggrep-setting*
           *ggrep-setting-history*)))
    (dolist (variable history-variables)
      (unregister-history-variable variable)))
  (delete-command-bar 'ggrep-tool-bar)
  (ggrep-delete-menu))

(if (menup ed::*app-menu*)
    (ggrep-insert-menu-items)
  (add-hook 'ed::*init-app-menus-hook*
            #'(lambda () (ggrep-insert-menu-items))))

;;; ggrep.l ends here
