root/lang/elisp/perl-completion/branch/1.0/perl-completion.el @ 19697

Revision 19697, 74.6 kB (checked in by imakado, 5 years ago)

キーバインドを追加。anything起動中のキーバインドを追加。PERL5LIBに追加する際に末尾に:が入ってしまう場合があったのに対応。非同期でインストールされているモジュールを収得する際に前回の結果がクリアされていなかったのを修正。plcmp-get-module-file-pathがフルパスを返すように。他のperlバッファから補完候補を収得する部分にキャッシュを実装。

Line 
1;;;  -*- coding: utf-8; mode: emacs-lisp; -*-
2;;; perl-completion.el
3
4;; Author: Kenji.Imakado <ken.imakaado@gmail.com>
5;; Keywords: perl
6
7;; This file is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 2, or (at your option)
10;; any later version.
11
12;; This file is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs; see the file COPYING.  If not, write to the
19;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20;; Boston, MA 02110-1301, USA.
21
22;; Prefix: plcmp-
23
24;;; Commentary:
25;; Tested on Emacs 22
26
27;; to customize
28;; M-x customize-group RET perl-completion RET
29
30
31;; TODO:
32;; plcmp-cmd-show-environment
33
34;;;code:
35(require 'cl)
36(require 'anything) ; perl-completion.el uses `anything-aif' macro.
37(require 'cperl-mode)
38(require 'dabbrev)
39(require 'rx)
40
41
42;;; customize-variables
43(defgroup perl-completion nil
44  ""
45  :group 'perl-completion)
46
47(defcustom plcmp-lib-directory-re "lib/"
48  "regexp, used in `plcmp--get-lib-path' to get library path.
49eg, when directory of buffer is \"~/someproject/lib/hoge.pm\" and this value is \"lib/\"
50set \"~/someproject/lib\" to PERL5LIB automatically during perl-completion's command invocation."
51    :group 'perl-completion)
52
53;;; log util
54(defvar plcmp-debug nil)
55(defvar plcmp-log-buf-name "*plcmp debug*")
56(defun plcmp-log-buf ()
57  (get-buffer-create plcmp-log-buf-name))
58(defsubst plcmp-log (&rest messages)
59  (ignore-errors
60    (when plcmp-debug
61      (require 'pp)
62      (let* ((str (or (ignore-errors (apply 'format messages))
63                      (pp-to-string (car messages))))
64             (strn (concat str "\n")))
65        (with-current-buffer (plcmp-log-buf)
66          (goto-char (point-max))
67          (insert strn))
68        str))))
69(defun plcmp-message (&rest args)
70  (when plcmp-debug
71    (prog1 (apply 'message args)
72      (apply 'plcmp-log args))))
73
74
75;;; variables
76(defvar plcmp-version 1.0)
77
78(defvar plcmp-perl-ident-re "[a-zA-Z_][a-zA-Z_0-9]*")
79
80(defvar plcmp-sub-re (rx-to-string `(and "sub"
81                                        (+ space)
82                                        (group
83                                         (regexp ,plcmp-perl-ident-re)))))
84
85(defvar plcmp-perl-package-re "[a-zA-Z_][a-zA-Z0-9_:]*")
86
87(defvar plcmp-builtin-functions
88  '("abs" "exec" "glob" "order" "seek" "symlink" "accept" "exists" "gmtime"
89    "our" "seekdir" "syscall" "alarm" "exit" "goto" "pack" "select" "sysopen"
90    "atan" "exp" "grep" "package" "semctl" "sysread" "bind" "fcntl" "hex"
91    "pipe" "semget" "sysseek" "binmode" "fileno" "import" "pop" "semop"
92    "system" "bless" "flags" "index" "pos" "send" "syswrite" "caller" "flock"
93    "int" "precision" "setgrent" "tell" "chdir" "fork" "ioctl" "print" "sethostent"
94    "telldir" "chmod" "format" "join" "printf" "setnetent" "tie" "chomp" "formline"
95    "keys" "prototype" "setpgrp" "tied" "chop" "getc" "kill" "push" "setpriority"
96    "time" "chown" "getgrent" "last" "q" "setprotoent" "times" "chr" "getgrgid"
97    "lc" "qq" "setpwent" "tr" "chroot" "getgrnam" "lcfirst" "qr" "setservent"
98    "truncate" "close" "gethostbyaddr" "length" "quotemeta" "setsockopt" "uc"
99    "closedir" "gethostbyname" "link" "qw" "shift" "ucfirst" "connect" "gethostent"
100    "listen" "qx" "shmctl" "umask" "continue" "getlogin" "local" "rand" "shmget"
101    "undef" "cos" "getnetbyaddr" "localtime" "read" "shmread" "unlink" "crypt"
102    "getnetbyname" "lock" "readdir" "shmwrite" "unpack" "dbmclose" "getnetent"
103    "log" "readline" "shutdown" "unshift" "dbmopen" "getpeername" "lstat" "readlink"
104    "sin" "untie" "defined" "getpgrp" "m" "readpipe" "size" "use" "delete" "getppid"
105    "map" "recv" "sleep" "utime" "die" "getpriority" "mkdir" "redo" "socket" "values"
106    "do" "getprotobyname" "msgctl" "ref" "socketpair" "vec" "dump" "getprotobynumber"
107    "msgget" "rename" "sort" "vector" "each" "getprotoent" "msgrcv" "require" "splice"
108    "wait" "endgrent" "getpwent" "msgsnd" "reset" "split" "waitpid" "endhostent"
109    "getpwnam" "my" "return" "sprintf" "wantarray" "endnetent" "getpwuid" "next"
110    "reverse" "sqrt" "warn" "endprotoent" "getservbyname" "no" "rewinddir" "srand"
111    "write" "endpwent" "getservbyport" "oct" "rindex" "stat" "y" "endservent" "getservent"
112    "open" "rmdir" "study" "eof" "getsockname" "opendir" "s" "sub" "eval" "getsockopt"
113    "ord" "scalar" "substr"))
114
115(defvar plcmp-builtin-variables
116  '("$SIG{expr}" "%SIG" "$ENV{expr}" "%ENV" "%INC" "@_" "@INC" "@F" "ARGVOUT"
117    "@ARGV" "$ARGV" "ARGV" "$^X" "$EXECUTABLE_NAME" "${^WARNING_BITS}" "$^W"
118    "$WARNING" "$^V" "$PERL_VERSION" "${^UTF8LOCALE}" "${^UNICODE}" "${^TAINT}"
119    "$^T" "$BASETIME" "$^S" "$EXCEPTIONS_BEING_CAUGHT" "$^R"
120    "$LAST_REGEXP_CODE_RESULT" "$^P" "$PERLDB" "${^OPEN}" "$^O" "$OSNAME" "$^M" "$^I" "$INPLACE_EDIT"
121    "%^H" "$^H" "$^F" "$SYSTEM_FD_MAX" "$^D" "$DEBUGGING" "$^C" "$COMPILING" "$]"
122    "$[" "$0" "$PROGRAM_NAME" "$)" "$EGID" "$EFFECTIVE_GROUP_ID" "$(" "$GID" "$REAL_GROUP_ID"
123    "$>" "$EUID" "$EFFECTIVE_USER_ID" "$<" "$UID" "$REAL_USER_ID" "$$" "$PID" "$PROCESS_ID"
124    "$@" "$EVAL_ERROR" "$^E" "$EXTENDED_OS_ERROR" "%!" "$!" "$ERRNO" "$OS_ERROR" "${^ENCODING}"
125    "$?" "$CHILD_ERROR" "$^A" "$ACCUMULATOR" "$^L" "$FORMAT_FORMFEED" "IO::Handle->format_formfeed" "$:"
126    "$FORMAT_LINE_BREAK_CHARACTERS" "IO::Handle->format_line_break_characters" "$^"
127    "$FORMAT_TOP_NAME" "HANDLE->format_top_name(EXPR)" "$~"
128    "$FORMAT_NAME" "HANDLE->format_name(EXPR)" "@-" "@LAST_MATCH_START"
129    "$-" "$FORMAT_LINES_LEFT" "HANDLE->format_lines_left(EXPR)" "$="
130    "$FORMAT_LINES_PER_PAGE" "HANDLE->format_lines_per_page(EXPR)" "$%"
131    "$FORMAT_PAGE_NUMBER" "HANDLE->format_page_number(EXPR)" "$#" "$;"
132    "$SUBSEP" "$SUBSCRIPT_SEPARATOR" "$\"" "$LIST_SEPARATOR" "$\\" "$ORS"
133    "$OUTPUT_RECORD_SEPARATOR" "IO::Handle->output_record_separator" "$," "$OFS"
134    "$OUTPUT_FIELD_SEPARATOR" "IO::Handle->output_field_separator" "$|"
135    "$OUTPUT_AUTOFLUSH" "HANDLE->autoflush(EXPR)" "$/" "$RS"
136    "$INPUT_RECORD_SEPARATOR" "IO::Handle->input_record_separator(EXPR)" "$."
137    "$NR" "$INPUT_LINE_NUMBER" "HANDLE->input_line_number(EXPR)" "$*" "@+"
138    "@LAST_MATCH_END" "$^N" "$+" "$LAST_PAREN_MATCH" "$'" "$POSTMATCH" "$`"
139    "$PREMATCH" "$&" "$MATCH" "$<digits>" "$b" "$a" "$_" "$ARG"))
140
141(defvar plcmp--command-cleanup-hook nil "hook run when completion command finished")
142
143(defvar plcmp--cached-variables nil "list of cached variable. each variable is cleared by `plcmp-cmd-clear-all-caches'")
144
145(defvar plcmp-clear-all-caches-hook nil
146  "hook run when invoke `plcmp-cmd-clear-all-caches'")
147
148
149;;; keymap
150(defvar plcmp-mode-map
151  (let ((map (make-sparse-keymap)))
152    ;; completion
153    (define-key map (kbd "C-RET") 'plcmp-cmd-smart-complete)
154    (define-key map (kbd "C-<return>") 'plcmp-cmd-smart-complete)
155    (define-key map (kbd "C-M-i") 'plcmp-cmd-smart-complete)
156    (define-key map (kbd "C-c a") 'plcmp-cmd-complete-arrays)
157    (define-key map (kbd "C-c i") 'plcmp-cmd-complete-modules)
158    (define-key map (kbd "C-c v") 'plcmp-cmd-complete-variables)
159    (define-key map (kbd "C-c f") 'plcmp-cmd-complete-functions)
160    (define-key map (kbd "C-c h") 'plcmp-cmd-complete-hashes)
161    (define-key map (kbd "C-c m") 'plcmp-cmd-complete-methods)
162    (define-key map (kbd "C-c C-c a") 'plcmp-cmd-complete-all)
163
164    ;; doc
165    (define-key map (kbd "C-c d") 'plcmp-cmd-show-doc)
166    (define-key map (kbd "C-c s") 'plcmp-cmd-show-doc-at-point)
167    (define-key map (kbd "C-c M") 'plcmp-cmd-menu)
168
169    ;; other
170    (define-key map (kbd "C-c c") 'plcmp-cmd-clear-all-caches)
171    (define-key map (kbd "C-c C-c s") 'plcmp-cmd-show-environment)
172    (define-key map (kbd "C-c C-c u") 'plcmp-cmd-update-check)
173    (define-key map (kbd "C-c C-c d") 'plcmp-cmd-set-additional-lib-directory)
174   
175    map))
176
177(defvar plcmp-anything-map
178  (let ((map (make-sparse-keymap)))
179      (define-key map (kbd "O") 'plcmp-acmd-occur)
180      (define-key map (kbd "D") 'plcmp-acmd-show-doc)
181      (define-key map (kbd "F") 'plcmp-acmd-open-related-file)
182      (define-key map (kbd "G") 'plcmp-acmd-goto-looking-point)
183      (define-key map (kbd "J") 'scroll-other-window)
184      (define-key map (kbd "K") 'scroll-other-window-down)
185      (define-key map (kbd "L") 'plcmp-acmd-persistent-look)     
186      (set-keymap-parent map anything-map)
187     
188      map))
189
190
191;;; macros
192
193;; perl5 lib
194;; idea: http://svn.coderepos.org/share/lang/elisp/set-perl5lib/set-perl5lib.el
195;;       http://d.hatena.ne.jp/sun-basix/20080117/1200528765 (Japanese)
196(defvar plcmp-additional-lib-directories nil
197  "list of string(directory),each directory set to PERL5LIB during perl-completion's command invocation.
198this variable is buffer local") ;buffer local
199(make-variable-buffer-local 'plcmp-additional-lib-directories)
200
201
202(defun plcmp--get-lib-path ()
203  "return string(additional library path)"
204  (let ((dir (plcmp-get-current-directory))
205        (lib-re (rx-to-string `(and (group
206                                     bol
207                                     (* not-newline)
208                                     ,plcmp-lib-directory-re)))))
209    (when (string-match lib-re dir)
210      (let ((lib-dir (match-string 1 dir)))
211        (and (stringp lib-dir)
212             (file-exists-p lib-dir)
213             (directory-file-name lib-dir))))))
214
215(defmacro plcmp-with-set-perl5-lib (&rest body)
216  "Set each path that value of `plcmp--get-lib-path' to PERL5LIB.
217then execute BODY"
218  `(let ((process-environment (copy-sequence process-environment)))
219     (require 'env)
220     (let ((additional-lib-list (append plcmp-additional-lib-directories
221                                        (when (plcmp--get-lib-path)
222                                          (list (plcmp--get-lib-path)))))
223           (old-perl5lib (or (getenv "PERL5LIB") "")))
224       (when additional-lib-list
225         (let* ((additional-lib-str (mapconcat 'identity additional-lib-list path-separator))
226                (current-perl5lib (concat additional-lib-str path-separator old-perl5lib))
227                (current-perl5lib (replace-regexp-in-string ":$" "" current-perl5lib)))
228           (when (and (stringp current-perl5lib)
229                      (not (equal "" current-perl5lib)))
230             (setenv "PERL5LIB" current-perl5lib)
231             (plcmp-log "plcmp-with-set-perl5-lib PERL5LIB: %s" current-perl5lib)))))
232     (progn
233       ,@body)))
234
235
236(defmacro define-plcmp-command (command-name-with-no-prefix args &rest body)
237  (let* ((prefix "plcmp-cmd-")
238         (command-str (symbol-name command-name-with-no-prefix))
239         (command-name (concat prefix command-str)))
240    `(defun* ,(intern command-name) ,args
241       (interactive)
242       (unwind-protect
243           (let ((anything-map plcmp-anything-map))
244             (plcmp-with-set-perl5-lib
245              (progn (plcmp-initialize-variables)
246                     ,@body)))
247         (plcmp-cleanup)))))
248(put 'define-plcmp-command 'lisp-indent-function 'defun)
249(def-edebug-spec define-plcmp-command defun*)
250
251(defmacro plcmp-ignore-errors (&rest body)
252  `(condition-case e (progn ,@body)
253     (error (plcmp-log "Error plcmp-ignore-errors :  %s" (error-message-string e)))))
254(def-edebug-spec plcmp-ignore-errors ignore-errors)
255
256;;; Util functions
257(defsubst plcmp-trim (s)
258  "strip space and newline"
259  (replace-regexp-in-string
260   "[ \t\n]*$" "" (replace-regexp-in-string "^[ \t\n]*" "" s)))
261
262(defsubst plcmp-bit-regexp-p (s)
263  (string-match "^[/:$@&%(),.?<>+!|^*';\"\\]+$" s))
264
265(defsubst plcmp-module-p (s)
266  (string-match "^[a-zA-Z:]+$" s))
267
268(defsubst plcmp-perl-identifier-p (s)
269  (string-match (concat "^" plcmp-perl-ident-re "$") s))
270
271(defsubst plcmp-notfound-p (s)
272  (anything-aif (string-match "^Can't locate [^ \t]+ in" s)
273      (prog1 it
274        (plcmp-log "module notfound errmsg: %s" s))))
275
276(defsubst plcmp-tramp-p ()
277  (when (and (featurep 'tramp)
278             (fboundp 'tramp-tramp-file-p))
279    (let* ((dir (plcmp-get-current-directory))
280           (tramp? (tramp-tramp-file-p dir)))
281      (when tramp?
282        (prog1 tramp?
283          (plcmp-log "plcmp-tramp-p return non-nil: %s" dir))))))
284
285(defsubst plcmp-insert-each-line (los)
286  (insert (mapconcat 'identity los "\n")))
287
288(defun plcmp-get-current-directory ()
289  (file-name-directory
290   (expand-file-name
291    (or (buffer-file-name)
292        default-directory))))
293
294;; TODO: need test.
295(defsubst plcmp--re-match-sources1 (regexps source)
296  (when source
297    (let ((source (if (listp source) source (symbol-value source))))
298      (some (lambda (re)
299              (string-match re (assoc-default 'name source 'eq)))
300            regexps))))
301
302(defun plcmp-re-sort-sources (regexps sources &optional reverse)
303  (condition-case e
304      (let* ((regexps (if (stringp regexps) (list regexps) regexps))
305             (match-sources)
306             (unmatch-sources)
307             (sorted-sources
308              (loop for source in sources
309                    if (plcmp--re-match-sources1 regexps source)
310                    collect source into match-sources
311                    else
312                    collect source into unmatch-sources
313                    finally return (if reverse
314                                       (nconc unmatch-sources match-sources)
315                                     (nconc match-sources unmatch-sources)))))
316        sorted-sources)
317    (error (plcmp-log "Error: plcmp-re-sort-sources\nregexps: %s\nsources: %s"
318                      regexps
319                      sources)
320           sources)))
321
322(defsubst* plcmp-collect-matches
323    (re &optional (count 0) (match-string-fn 'match-string)
324        (point-min (point-min)) (point-max (point-max)))
325  (save-excursion
326    (loop initially (goto-char point-min)
327          while (re-search-forward re point-max t)
328          collect (funcall match-string-fn count))))
329
330(defun plcmp-get-occur-fn ()
331  "return `occur-by-moccur if installed color-moccur.el otherwise return `occur"
332  (if (require 'color-moccur nil t)
333      'occur-by-moccur
334    'occur))
335
336
337
338;;; initial-input
339(defvar plcmp-initial-input "")
340(defvar plcmp-real-initial-input "real initial-input if required `anything-match-plugin' initial-input is not real initial-input")
341
342(defun plcmp--fullname ()
343  (save-excursion
344    (let ((start (point)))
345      (skip-chars-backward "a-zA-Z0-9_")
346      (let ((str (plcmp-preceding-string 2)))
347        (when (string-equal str "::")
348          (buffer-substring-no-properties start (point)))))))
349
350
351(defun plcmp-get-initial-real-input-list ()
352  "return list (initial-input real-initial-input)"
353  (save-excursion
354    (let* ((start (point))
355           (real-initial-input
356            (cond
357             ((plcmp--fullname))
358             (t
359              (skip-syntax-backward "w_")
360              (let* ((preceding-string (char-to-string (preceding-char)))
361                     (end (condition-case e
362                              (cond
363                               ((some (lambda (s) (string-equal s preceding-string)) '("$" "@" "%" "&"))
364                                (backward-char)
365                                (point))
366                               (t
367                                (point)))
368                            (error (point)))))
369                (buffer-substring-no-properties start end)))))
370           (initial-input
371            (regexp-quote
372             (concat real-initial-input
373                     (if (and (featurep 'anything-match-plugin)
374                              (not (string-equal real-initial-input "")))
375                         " "
376                       "")))))
377      (prog1 (values initial-input real-initial-input)
378        (plcmp-log "plcmp-get-initial-real-input-list:\ninitial-input: %s\nreal-initial-input: %s"
379                   initial-input
380                   real-initial-input)))))
381
382
383;;; installed modules
384(defvar plcmp-installed-modules nil)
385(add-to-list 'plcmp--cached-variables 'plcmp-installed-modules)
386
387(defun plcmp-get-installed-modules ()
388  (unless (plcmp-tramp-p)
389    (or plcmp-installed-modules
390        (setq plcmp-installed-modules
391              (plcmp--installed-modules-synchronously)))))
392
393(defun plcmp--installed-modules-synchronously ()
394  (message "fetching installed modules...")
395  (let* ((modules-str (shell-command-to-string
396                       (concat
397                        "find `perl -e 'pop @INC; print join(q{ }, @INC);'`"
398                        " -name '*.pm' -type f "
399                        "| xargs egrep -h -o 'package [a-zA-Z0-9:]+;' "
400                        "| perl -nle 's/package\s+(.+);/$1/; print' "
401                        "| sort "
402                        "| uniq "
403                        )))
404         (modules (split-string modules-str "\n")))
405    (message "done")
406    (remove-if (lambda (module)
407                 (string-match "No such file or directory$" module))
408               modules)))
409
410(defvar plcmp-installed-modules-buffer-name " *perl-completion installed modules*")
411(defun plcmp--installed-modules-set-cache (process event)
412  (when (string-equal "finished\n" event)
413    (with-current-buffer plcmp-installed-modules-buffer-name
414      (unless (zerop (buffer-size))
415        (setq plcmp-installed-modules (plcmp-collect-matches plcmp-perl-package-re))
416        (message "finished getting installed modules asynchronously.")
417        (plcmp-log "cached installed modules %s" plcmp-installed-modules)))))
418
419(defun plcmp--installed-modules-asynchronously ()
420  "start process, set sentinel, return process."
421  (unless (plcmp-tramp-p)
422    (message "fetching installed modules...")
423    (with-current-buffer (get-buffer-create plcmp-installed-modules-buffer-name)
424      (erase-buffer))
425    (let* ((command "find")
426           (args (concat "`perl -e 'pop @INC; print join(q{ }, @INC);'`"
427                         " -name '*.pm' -type f "
428                         "| xargs grep -E -h -o 'package [a-zA-Z0-9:]+;' "
429                         "| perl -nle 's/package\s+(.+);/$1/; print' "
430                         "| sort "
431                         "| uniq "))
432           (proc (start-process-shell-command "installed perl modules"
433                                              plcmp-installed-modules-buffer-name
434                                              command
435                                              args)))
436      (set-process-sentinel proc 'plcmp--installed-modules-set-cache)
437      ;; return process
438      proc)))
439
440
441;;; current package
442(defvar plcmp-current-package-name "")
443(defun plcmp-get-current-package-name ()
444  "nil or string"
445  (let ((re (rx-to-string `(and bol
446                                (* space)
447                                "package"
448                                (* space)
449                                (group
450                                 (regexp ,plcmp-perl-package-re))
451                                (* not-newline)
452                                ";"))))
453    (save-excursion
454      (goto-char (point-min))
455      (when (re-search-forward re nil t)
456        (match-string-no-properties 1)))))
457
458(defvar plcmp-using-modules nil)
459(defun plcmp-get-using-modules ()
460  (let ((re (rx-to-string ` (and bol
461                                 (* space)
462                                 "use"
463                                 (+ space)
464                                    (group  ;1 package
465                                     (regexp ,plcmp-perl-package-re))
466                                    (* not-newline)
467                                    ";")))
468        (require-re (rx-to-string `(and "require"
469                                        (+ space)
470                                        (group
471                                         (regexp ,plcmp-perl-package-re))))))
472    (nunion (plcmp-collect-matches re 1 'match-string-no-properties)
473            (delete-if-not (lambda (s)
474                             (member s plcmp-installed-modules))
475                           (plcmp-collect-matches require-re 1 'match-string-no-properties))
476            :test 'string-equal)))
477
478;;; methods
479(defvar plcmp-obj-instance-of-module-maybe-alist nil)
480(defun plcmp-get-obj-instance-of-module-maybe-alist (using-modules)
481  (let* ((using-module-re (regexp-opt using-modules))
482         (re (rx-to-string `(and (group "$" ;1
483                                  (regexp ,plcmp-perl-ident-re))
484                                 (* space)
485                                 "="
486                                 (* space)
487                                 (group      ;2 module-name
488                                  (regexp ,using-module-re))))))
489    (save-excursion
490      (loop initially (goto-char (point-min))
491            while (re-search-forward re nil t)
492            collect `(,(match-string-no-properties 1) . ,(match-string-no-properties 2))))))
493
494(defsubst plcmp--make-los (str)
495  (with-temp-buffer
496    (insert str)
497    (plcmp-collect-matches plcmp-perl-ident-re)))
498
499(defsubst plcmp--inspect-module-class-inspector (module-name)
500  "Class::Inspectorを使用してモジュールのメソッド調べる。
501モジュール名に使用でき-る文字以外が含まれていた場合はnilを返す
502return alist (module-name . list of methods)"
503  (when (plcmp-module-p module-name)
504    (let ((modules-str
505           (shell-command-to-string
506            (concat "perl -MClass::Inspector -e'use "
507                    module-name
508                    "; print join \"\n\"=>@{Class::Inspector->methods("
509                    module-name
510                    ")} '"))))
511      (when (and (not (plcmp-notfound-p modules-str))
512                 (stringp modules-str))
513        (let ((modules (plcmp--make-los modules-str)))
514          `(,module-name . ,modules))))))
515
516(defsubst plcmp-get-buffer-subs ()
517  (plcmp-collect-matches plcmp-sub-re 1 'match-string-no-properties))
518
519(defun plcmp-get-module-file-path (module-name)
520  (let* ((path (shell-command-to-string (concat "perldoc -l " (shell-quote-argument module-name))))
521         (path (plcmp-trim path)))
522    (and (stringp path)
523         (file-exists-p path)
524         (expand-file-name path))))
525
526(defun plcmp--inspect-module-scrape (module-name)
527  (when (and (stringp module-name)
528             (plcmp-module-p module-name))
529    (let* ((path (plcmp-get-module-file-path module-name)))
530      (when (and (stringp path)
531                 (file-exists-p path)
532                 (file-readable-p path))
533        (with-temp-buffer
534          (insert-file-contents path)
535          (plcmp-get-buffer-subs))))))
536
537(defsubst plcmp--inspect-module (module-name)
538  (prog1 (or (plcmp--inspect-module-class-inspector module-name)
539             (plcmp--inspect-module-scrape module-name))
540    (message "getting methods %s ..." module-name)))
541
542(defvar plcmp-module-methods-alist nil
543  "alist, (module-name . (list of methods))")
544(add-to-list 'plcmp--cached-variables 'plcmp-module-methods-alist)
545
546
547(defun plcmp-get-module-methods-alist (using-modules)
548  (dolist (module-name using-modules plcmp-module-methods-alist)
549    (unless (assoc module-name plcmp-module-methods-alist)
550      (add-to-list 'plcmp-module-methods-alist
551                   (plcmp--inspect-module module-name)))))
552
553
554;; module-name -> source
555(defvar plcmp--mk-module-source-name " Methods")
556
557(defsubst plcmp--mk-module-source (module-name)
558  (anything-aif (assoc-default module-name plcmp-module-methods-alist)
559      `((name . ,(concat module-name plcmp--mk-module-source-name))
560        (action . (("Insert" . plcmp-insert)
561                   ("Show doc" .
562                    (lambda (candidate)
563                      (let* ((module (plcmp-get-current-module-name))
564                             (buf (plcmp-get-man-buffer module 'module)))
565                        (save-selected-window
566                          (pop-to-buffer buf)))))
567                   ("Show doc and go" .
568                    (lambda (candidate)
569                      (let* ((module (plcmp-get-current-module-name))
570                             (buf (plcmp-get-man-buffer module 'module)))
571                        (pop-to-buffer buf))))
572                   ("Open module file" .
573                    (lambda (method)
574                      (let ((module (plcmp-get-current-module-name)))
575                        (plcmp-open-module-file module))))
576                   ("Open module file other window" .
577                    (lambda (method)
578                      (let ((module-name (plcmp-get-current-module-name)))
579                        (plcmp-open-module-file module-name 'pop-to-buffer))))
580                   ("Open module file other frame" .
581                    (lambda (candidate)
582                      (let ((module-name (plcmp-get-current-module-name)))
583                        (plcmp-open-module-file module-name
584                                                'switch-to-buffer-other-frame))))
585                   ("Occur module file" .
586                    (lambda (candidate)
587                      (let ((module-name (plcmp-get-current-module-name)))
588                        (plcmp-open-module-file module-name
589                                                'switch-to-buffer)
590                        (funcall (plcmp-get-occur-fn)
591                                 candidate
592                                  nil))))
593                   ("Add to kill-ring" . kill-new)
594                   ("Insert source name" .
595                    (lambda (candidate)
596                      (let ((name (plcmp-anything-get-current-source-name)))
597                        (and (stringp name)
598                             (insert name)))))
599                   ))
600        (init . (lambda ()
601                  (with-current-buffer (anything-candidate-buffer 'global)
602                    (plcmp-insert-each-line ',it))))
603        (candidates-in-buffer)
604        (persistent-action . (lambda (candidate)
605                               (let ((module-name (plcmp-get-current-module-name)))
606                                 (plcmp-open-doc module-name)
607                                 (plcmp-re-search-forward-fontify (regexp-quote candidate)))))
608        )))
609
610
611;; plcmp-using-modules -> sources
612(defun plcmp-get-sources-methods (using-modules)
613  (loop for module-name in using-modules
614        collect (plcmp--mk-module-source module-name)))
615
616
617;;; dabbrev
618(defvar plcmp-buffer-dabbrevs-re
619  (rx (>= 4 (or (syntax word)
620                (syntax symbol)))))
621
622(defsubst* plcmp-get-buffer-dabbrevs ()
623  (plcmp-collect-matches plcmp-buffer-dabbrevs-re))
624
625;;; current buffer words
626(defsubst* plcmp--check-face (face-names &optional (point (point)))
627  (let* ((face (get-text-property point 'face))
628         (faces (if (listp face) face (list face))))
629    (some (lambda (face-sym)
630            (memq face-sym faces))
631          face-names)))
632
633(defsubst* plcmp-get-face-words (&optional (faces '(font-lock-variable-name-face
634                                                    font-lock-function-name-face)))
635  (let ((hash (make-hash-table :test 'equal))
636        (ret nil))
637    (save-excursion
638      (loop initially (goto-char (point-min))
639            for next-change = (or (next-property-change (point) (current-buffer))
640                                  (point-max))
641            until (eobp)
642            do (progn (when (plcmp--check-face faces)
643                        (anything-aif (cperl-word-at-point)
644                            (puthash it nil hash)))
645                      (goto-char next-change)))
646      (maphash (lambda (k v) (push k ret)) hash) ; remove-dups
647      (nreverse ret))))
648
649;;; other buffer words
650(defvar plcmp-perl-buffer-re "\\.p[lm]$")
651(defvar plcmp-other-perl-buffer-limit-number 30)
652(defvar plcmp-other-perl-buffers-words-faces
653  '(font-lock-function-name-face
654    font-lock-variable-name-face
655    font-lock-keyword-face
656    font-lock-builtin-face
657    font-lock-type-face
658    cperl-array-face
659    cperl-hash-face))
660
661;; cache
662(defvar plcmp-buffer-tick-hash (make-hash-table :test 'equal))
663(defun* plcmp-buffer-is-modified (&optional (buffer (current-buffer)))
664  "Return non-nil when BUFFER is modified since `anything' was invoked."
665  (let* ((key (concat (buffer-name buffer)
666                      "/"
667                      (anything-attr 'name)))
668         (source-tick (or (gethash key plcmp-buffer-tick-hash) 0))
669         (buffer-tick (buffer-chars-modified-tick buffer)))
670    (prog1 (/= source-tick buffer-tick)
671      (puthash key buffer-tick plcmp-buffer-tick-hash)
672      (plcmp-log "plcmp-buffer-is-modified")
673      (plcmp-log "current-buffer: %s" buffer)
674      (plcmp-log "source-tick: %s\nbuffer-tick: %s" source-tick buffer-tick))))
675
676
677(defvar plcmp-other-perl-buffers-cache-hash (make-hash-table :test 'equal))
678(add-hook 'plcmp-clear-all-caches-hook
679          (lambda ()
680            (setq plcmp-other-perl-buffers-cache-hash
681                  (make-hash-table :test 'equal))))
682
683(defun plcmp-add-to-other-perl-buffers-cache-hash (source-name faces buffer-name)
684  (let ((hash (or (gethash source-name plcmp-other-perl-buffers-cache-hash)
685                  (puthash source-name
686                           (make-hash-table :test 'equal)
687                           plcmp-other-perl-buffers-cache-hash)))
688        (words (plcmp-get-face-words faces)))
689    (assert (hash-table-p hash))
690    (puthash buffer-name
691             words
692             hash)
693    (prog1 words
694      (plcmp-log "\nplcmp-add-to-other-perl-buffers-cache-hash: %s"
695                 words))))
696
697(defun plcmp-get-other-perl-buffers-cache (source-name buffer-name)
698  "return los or nil if not cache ready"
699  (let ((hash (gethash source-name plcmp-other-perl-buffers-cache-hash)))
700    (and (hash-table-p hash)
701         (prog1 (gethash buffer-name hash)
702           (plcmp-log "plcmp-get-other-perl-buffers-cache: %s"
703                      (gethash buffer-name hash))))))
704
705(defun plcmp-other-perl-buffers-get-buffer-name ()
706  "return buffer or nil"
707  (let ((source-name (anything-attr 'name)))
708    (when (string-match (rx " *" (group (* not-newline)) "*" eol)
709                        source-name)
710      (let ((buffer-name (match-string 1 source-name)))
711        (when (stringp buffer-name)
712          (let ((buffer (get-buffer buffer-name)))
713            (and (bufferp buffer)
714                 buffer)))))))
715
716(defun plcmp-other-perl-buffers-action-open-related-buffer (candidate)
717  (let ((buffer (plcmp-other-perl-buffers-get-buffer-name)))
718    (switch-to-buffer buffer)))
719
720(defun plcmp-other-perl-buffers-action-occur (candidate)
721  (let ((buffer (plcmp-other-perl-buffers-get-buffer-name)))
722    (switch-to-buffer buffer)
723    (funcall (plcmp-get-occur-fn)
724             (regexp-quote candidate)
725             nil)))
726
727(defun plcmp--mk-other-perl-buffer-source (source-name faces buffer-name)
728  `((name . ,(concat source-name " *" buffer-name "*"))
729    (action . (("Insert" . plcmp-insert)
730               ("Open related buffer" . plcmp-other-perl-buffers-action-open-related-buffer)
731               ("Occur" . plcmp-other-perl-buffers-action-occur)))
732    (init . (lambda ()
733              (let ((words (with-current-buffer (get-buffer ,buffer-name)
734                             (anything-aif (and (not (plcmp-buffer-is-modified))
735                                                (plcmp-get-other-perl-buffers-cache ,source-name ,buffer-name))
736                                 (prog1 it
737                                   (plcmp-log "return cache buffer: %s source-name: %s "
738                                              ,buffer-name
739                                              ,source-name))
740                               (prog1 (plcmp-add-to-other-perl-buffers-cache-hash
741                                       ,source-name
742                                       ',faces
743                                       ,buffer-name)
744                                 (plcmp-log "modified: %s" ,buffer-name))))))
745                (with-current-buffer (anything-candidate-buffer 'global)
746                  (plcmp-insert-each-line words)))))
747    (candidates-in-buffer)
748    (persistent-action . (lambda (candidate)
749                           (let ((buffer (plcmp-other-perl-buffers-get-buffer-name)))
750                             (when (bufferp buffer)
751                               (switch-to-buffer buffer)
752                               (plcmp-re-search-forward-fontify (regexp-quote candidate))))))
753    ))
754
755(defun plcmp--sources-other-perl-buffers (source-name faces)
756  (let* ((perl-buffers (remove-if-not (lambda (buf)
757                                        (string-match plcmp-perl-buffer-re (buffer-name buf)))
758                                      (buffer-list)))
759         (perl-buffers (subseq perl-buffers 0 plcmp-other-perl-buffer-limit-number))
760         (sources (loop for buffer in perl-buffers
761                        when (bufferp buffer)
762                        collect (with-current-buffer buffer
763                                  (plcmp--mk-other-perl-buffer-source
764                                   source-name
765                                   faces
766                                   (buffer-name buffer))))))
767    (prog1 sources
768      (plcmp-log "plcmp--sources-other-perl-buffers:")
769      (plcmp-log sources))))
770
771(defun plcmp-get-sources-other-perl-buffers-words ()
772  (plcmp--sources-other-perl-buffers "words" plcmp-other-perl-buffers-words-faces))
773
774(defun plcmp-get-sources-other-perl-buffers-variable ()
775  (plcmp--sources-other-perl-buffers "variables" '(font-lock-variable-name-face)))
776
777(defun plcmp-get-sources-other-perl-buffers-hashes ()
778  (plcmp--sources-other-perl-buffers "hashes" '(cperl-hash-face)))
779
780(defun plcmp-get-sources-other-perl-buffers-arrays ()
781  (plcmp--sources-other-perl-buffers "arrays" '(cperl-array-face)))
782
783(defun plcmp-get-sources-other-perl-buffers-functions ()
784  (plcmp--sources-other-perl-buffers "functions" '(font-lock-function-name-face)))
785
786;;; man
787(defvar plcmp-man-pages
788  (condition-case nil
789      (let ((pages
790             (progn
791               (require 'woman)
792               (woman-file-name "")
793               (mapcar 'car
794                       woman-topic-all-completions))))
795        (remove-if-not (lambda (s)
796                         (or (member s plcmp-installed-modules)
797                             (string-match "perl" s)))
798                       pages))
799    (error nil)))
800
801
802;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
803;;;; Document
804;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805(defvar plcmp-look-overlay nil "overlay")
806(add-hook 'plcmp--command-cleanup-hook
807          (lambda ()
808            (when (overlayp plcmp-look-overlay)
809              (delete-overlay plcmp-look-overlay))))
810
811(defvar plcmp-look-current-positions nil
812  "list of (point buffer)
813point, after `plcmp-re-search-forward-fontify'")
814(add-hook 'plcmp--command-cleanup-hook
815          (lambda ()
816            (setq plcmp-look-current-positions nil)))
817
818(defun plcmp-re-search-forward-fontify (regexp)
819  (if (re-search-forward regexp nil t)
820      (let ((beg (match-beginning 0))
821            (end (match-end 0)))
822        ;; remember positions
823        (setq plcmp-look-current-positions (list (point) (current-buffer)))
824        (plcmp-log "plcmp-look-current-positions: %s" (list (point) (current-buffer)))
825     
826        (when (and beg end)
827          (if (overlayp plcmp-look-overlay)
828              (move-overlay plcmp-look-overlay beg end (current-buffer))
829            (setq plcmp-look-overlay (make-overlay beg end)))
830          (overlay-put plcmp-look-overlay 'face 'highlight)
831          (recenter 5)))
832    (goto-char (point-min))))
833
834
835;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
836;;;; Initialize, Cleanup
837;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838(defun plcmp-initialize-variables ()
839  (setq plcmp-installed-modules (plcmp-get-installed-modules)
840        plcmp-current-package-name (plcmp-get-current-package-name)
841        plcmp-using-modules (plcmp-get-using-modules)
842        plcmp-module-methods-alist (plcmp-get-module-methods-alist plcmp-using-modules)
843        plcmp-obj-instance-of-module-maybe-alist (plcmp-get-obj-instance-of-module-maybe-alist plcmp-using-modules))
844  (multiple-value-setq
845      (plcmp-initial-input plcmp-real-initial-input) (plcmp-get-initial-real-input-list)))
846
847(defun plcmp-cleanup ()
848  (run-hooks 'plcmp--command-cleanup-hook))
849
850;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851;;;; Anything
852;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853
854(defun plcmp--anything-get-current-source-name ()
855  "Return the source name for the current selection."
856  (declare (special source))
857  ;; The name `anything-get-current-source' should be used in init function etc.
858  (if (and (boundp 'anything-source-name) (stringp anything-source-name))
859      anything-source-name
860    (with-current-buffer (anything-buffer-get)
861      ;; This goto-char shouldn't be necessary, but point is moved to
862      ;; point-min somewhere else which shouldn't happen.
863      (goto-char (overlay-start anything-selection-overlay))
864      (let* ((header-pos (anything-get-previous-header-pos)))
865        (save-excursion
866          (assert header-pos)
867          (goto-char header-pos)
868          (prog1 (buffer-substring-no-properties
869                  (line-beginning-position) (line-end-position))
870            (plcmp-log "plcmp-anything-get-current-source-name: %s"
871                       (buffer-substring-no-properties
872                        (line-beginning-position) (line-end-position)))))))))
873
874(defun plcmp-get-current-module-name ()
875  (let* ((module (plcmp--anything-get-current-source-name)))
876    (when (string-match
877           (rx-to-string `(and
878                           bol
879                           (group
880                            (regexp ,plcmp-perl-package-re))
881                           ,plcmp--mk-module-source-name))
882           module)
883      (match-string 1 module))))
884
885;;;TODO
886(defun plcmp-completion-get-man-buffer (candidate)
887  "return manpage buffer ,called in completion source action"
888  (let* ((name (plcmp--anything-get-current-source-name))
889         (ret (cond
890               ((string-equal name "builtin functions")
891                (plcmp-get-man-buffer candidate 'function))
892               ((or (string-equal name "using modules")
893                    (string-equal name "installed modules"))
894                (plcmp-get-man-buffer candidate))
895               ((string-equal name "builtin variables")
896                (plcmp-get-man-buffer "" 'variables))
897               ((string-match (concat plcmp--mk-module-source-name "$")
898                              name)
899                (plcmp-get-current-module-name)))))
900    (prog1 ret
901      (plcmp-log "plcmp-completion-get-man-buffer candidate: %s return: %s"
902                 candidate
903                 ret))))
904
905
906(defvar plcmp-type-completion
907    '(plcmp-completion
908      (action . (("Insert" . plcmp-insert)
909                 ("Show man" .
910                  (lambda (candidate)
911                    (anything-aif (plcmp-completion-get-man-buffer candidate)
912                        (switch-to-buffer it))))
913                 ("Add to kill-ring" . kill-new)
914                 ("Insert source name" .
915                  (lambda (candidate)
916                    (let ((name (plcmp-anything-get-current-source-name)))
917                      (and (stringp name)
918                           (insert name)))))
919                 ))))
920(add-to-list 'anything-type-attributes plcmp-type-completion)
921
922(defvar plcmp-type-completion-method
923    '(plcmp-completion-method
924      (action . (("Insert" . plcmp-insert)
925                 ("Open module file" .
926                  (lambda (method)
927                    (let ((module (plcmp-get-current-module-name)))
928                      (plcmp-open-module-file module))))
929                 ("Open module file other window" .
930                  (lambda (method)
931                    (let ((module-name (plcmp-get-current-module-name)))
932                      (plcmp-open-module-file module-name 'pop-to-buffer))))
933                 ("Open module file other frame" .
934                  (lambda (candidate)
935                    (let ((module-name (plcmp-get-current-module-name)))
936                      (plcmp-open-module-file module-name
937                                              'switch-to-buffer-other-frame))))
938                 ("Add to kill-ring" . kill-new)
939                 ("Insert source name" .
940                  (lambda (candidate)
941                    (let ((name (plcmp-anything-get-current-source-name)))
942                      (and (stringp name)
943                           (insert name)))))
944                 ))))
945(add-to-list 'anything-type-attributes plcmp-type-completion-method)
946
947(defvar plcmp-type-man
948  '(plcmp-doc
949    (action . (("Show man" .
950                (lambda (candidate)
951                  (plcmp-open-doc candidate 'man)))
952               ("Show man other window" .
953                (lambda (candidate)
954                  (plcmp-open-doc candidate 'man 'pop-to-buffer)))
955               ("Show man other window and go" .
956                (lambda (candidate)
957                  (plcmp-open-doc candidate 'man 'switch-to-buffer-other-window)))
958               ("Show man other frame and go" .
959                (lambda (candidate)
960                  (plcmp-open-doc candidate 'man 'switch-to-buffer-other-frame)))
961               ("Occur man buffer" .
962                (lambda (candidate)
963                  (when (plcmp-open-doc candidate 'man)
964                    (call-interactively (plcmp-get-occur-fn)
965                                        (regexp-quote candidate)))))
966               ("Insert man name" . insert)
967               ("Add man name to kill-ring" . kill-new)))))
968
969(defvar plcmp-type-perldoc
970  '(plcmp-perldoc
971    (action . ())))
972(add-to-list 'anything-type-attributes plcmp-type-man)
973
974(defun plcmp-insert (candidate)
975  (delete-backward-char (length plcmp-real-initial-input))
976  (insert candidate))
977
978;;; perldoc
979(defun* plcmp-get-man-buffer (topic &optional (type 'module))
980  "like `Man-getpage-in-background' but call process synchronously.
981return buffer or nil unless process return 0"
982  (require 'man)
983  (let* ((manual-program (ecase type
984                           (module "perldoc")
985                           (man manual-program)
986                           (function "perldoc -f")
987                           (variable "perldoc perlvar")))
988         (command (if (eq type 'variable)
989                      manual-program
990                    (concat manual-program " " topic)))
991         (bufname (concat "*perldoc " topic "*"))
992         (buffer  (get-buffer-create bufname)))
993    (require 'env)
994    (let ((process-environment (copy-sequence process-environment))
995            ;; The following is so Awk script gets \n intact
996            ;; But don't prevent decoding of the outside.
997            (coding-system-for-write 'raw-text-unix)
998            ;; We must decode the output by a coding system that the
999            ;; system's locale suggests in multibyte mode.
1000            (coding-system-for-read
1001             (if default-enable-multibyte-characters
1002                 locale-coding-system 'raw-text-unix))
1003            ;; Avoid possible error by using a directory that always exists.
1004            (default-directory
1005              (if (and (file-directory-p default-directory)
1006                       (not (find-file-name-handler default-directory
1007                                                    'file-directory-p)))
1008                  default-directory
1009                "/")))
1010        ;; Prevent any attempt to use display terminal fanciness.
1011        (setenv "TERM" "dumb")
1012        (save-window-excursion (shell-command command bufname))
1013        (get-buffer bufname))))
1014
1015(defun* plcmp-open-doc (topic &optional (type 'module) (show-fn 'switch-to-buffer))
1016  (require 'man)
1017  (let ((manbuf (plcmp-get-man-buffer topic type)))
1018    (when (and (bufferp manbuf)
1019               (functionp show-fn))
1020      (funcall show-fn manbuf))))
1021
1022
1023;;; open module file
1024(defun plcmp--find-module-file-no-select (module-name)
1025  (when (plcmp-module-p module-name)
1026    (let ((path (plcmp-get-module-file-path module-name)))
1027      (when (and (stringp path)
1028                 (file-exists-p path)
1029                 (file-readable-p path))
1030        (find-file-noselect path)))))
1031
1032(defun* plcmp-open-module-file (module-name &optional (show-buffer-fn 'switch-to-buffer))
1033  (anything-aif (plcmp--find-module-file-no-select module-name)
1034      (funcall show-buffer-fn it)
1035    (message "can't find %s" module-name)))
1036
1037;;; sources
1038;; completion
1039(defvar plcmp-anything-source-completion-using-modules
1040  `((name . "using modules")
1041    (action . (("Insert" . plcmp-insert)
1042               ("Show doc" .
1043                (lambda (candidate)
1044                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1045                    (save-selected-window
1046                      (pop-to-buffer buf)))))
1047               ("Show doc and go" .
1048                (lambda (candidate)
1049                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1050                    (pop-to-buffer buf))))
1051               ("Occur" .
1052                (lambda (candidate)
1053                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1054                    (switch-to-buffer buf)
1055                    (call-interactively (plcmp-get-occur-fn)))))
1056               ("Open module file" .
1057                (lambda (candidate)
1058                  (plcmp-open-module-file candidate)))
1059               ("Open module file other window" .
1060                (lambda (candidate)
1061                  (plcmp-open-module-file candidate 'pop-to-buffer)))
1062               ("Open module file other frame" .
1063                (lambda (candidate)
1064                  (plcmp-open-module-file candidate
1065                                          'switch-to-buffer-other-frame)))
1066               ("Add to kill-ring" . kill-new)))
1067    (init . (lambda ()
1068              (with-current-buffer (anything-candidate-buffer 'global)
1069                (when plcmp-using-modules
1070                  (plcmp-insert-each-line plcmp-using-modules)))))
1071    (candidates-in-buffer)
1072    (persistent-action . (lambda (candidate)
1073                           (plcmp-open-doc candidate)
1074                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1075    ))
1076
1077(defvar plcmp-anything-source-completion-builtin-functions
1078  `((name . "builtin functions")
1079    (action . (("Insert" . plcmp-insert)
1080               ("Show doc" .
1081                (lambda (candidate)
1082                  (let ((buf (plcmp-get-man-buffer candidate 'function)))
1083                    (save-selected-window
1084                      (pop-to-buffer buf)))))
1085               ("Show doc and go" .
1086                (lambda (candidate)
1087                  (let ((buf (plcmp-get-man-buffer candidate 'function)))
1088                    (switch-to-buffer-other-window buf))))
1089               ("Occur" .
1090                (lambda (candidate)
1091                  (let ((buf (plcmp-get-man-buffer candidate 'function)))
1092                    (switch-to-buffer buf)
1093                    (funcall (plcmp-get-occur-fn)
1094                             (regexp-quote candidate)
1095                             nil))))
1096               ("Add to kill-ring" . kill-new)))
1097    (init . (lambda ()
1098              (with-current-buffer (anything-candidate-buffer 'global)
1099                (plcmp-insert-each-line plcmp-builtin-functions))))
1100    (candidates-in-buffer)
1101    (persistent-action . (lambda (candidate)
1102                           (plcmp-open-doc candidate 'function)
1103                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1104     ))
1105
1106(defvar plcmp-anything-source-completion-builtin-variables
1107  `((name . "builtin variables")
1108    (action . (("Insert" . plcmp-insert)
1109               ("Show doc" .
1110                (lambda (candidate)
1111                  (let ((buf (plcmp-get-man-buffer candidate 'variable))
1112                        (re (rx-to-string `(and bol (= 4 space)
1113                                                (group (eval ,candidate))
1114                                                (syntax whitespace)))))
1115                    (with-current-buffer buf
1116                      (re-search-forward re nil t))
1117                    (save-selected-window
1118                      (pop-to-buffer buf)))))
1119               ("Show doc and go" .
1120                (lambda (candidate)
1121                  (let ((buf (plcmp-get-man-buffer candidate 'variable))
1122                        (re (rx-to-string `(and bol (= 4 space)
1123                                                (group (eval ,candidate))
1124                                                (syntax whitespace)))))
1125                    (switch-to-buffer-other-window buf)
1126                    (re-search-forward re nil t))))
1127               ("Occur" .
1128                (lambda (candidate)
1129                  (let ((buf (plcmp-get-man-buffer candidate 'variable)))
1130                    (switch-to-buffer buf)
1131                    (funcall (plcmp-get-occur-fn)
1132                             (regexp-quote candidate)
1133                             nil))))
1134               ("Add to kill-ring" . kill-new)))
1135    (init . (lambda ()
1136              (with-current-buffer (anything-candidate-buffer 'global)
1137                (plcmp-insert-each-line plcmp-builtin-variables))))
1138    (candidates-in-buffer)
1139    (search . ((lambda (re arg1 arg2)
1140                 (re-search-forward (regexp-quote re) nil t))))
1141    (persistent-action . (lambda (candidate)
1142                           (plcmp-open-doc candidate 'variable)
1143                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1144    ))
1145
1146(defvar plcmp-anything-source-completion-installed-modules
1147  `((name . "installed modules")
1148    (action . (("Insert" . plcmp-insert)
1149               ("Show doc" .
1150                (lambda (candidate)
1151                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1152                    (save-selected-window
1153                      (pop-to-buffer buf)))))
1154               ("Show doc and go" .
1155                (lambda (candidate)
1156                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1157                    (pop-to-buffer buf))))
1158               ("Occur" .
1159                (lambda (candidate)
1160                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1161                    (switch-to-buffer buf)
1162                    (call-interactively (plcmp-get-occur-fn)))))
1163               ("Open module file" .
1164                (lambda (candidate)
1165                  (plcmp-open-module-file candidate)))
1166               ("Open module file other window" .
1167                (lambda (candidate)
1168                  (plcmp-open-module-file candidate 'pop-to-buffer)))
1169               ("Open module file other frame" .
1170                (lambda (candidate)
1171                  (plcmp-open-module-file candidate
1172                                          'switch-to-buffer-other-frame)))
1173               ("Add to kill-ring" . kill-new)))
1174    (init . (lambda ()
1175              (with-current-buffer (anything-candidate-buffer 'global)
1176                (let ((installed-modules (plcmp-get-installed-modules)))
1177                  (when installed-modules
1178                    (plcmp-insert-each-line installed-modules))))))
1179    (candidates-in-buffer)
1180    (persistent-action . (lambda (candidate)
1181                           (plcmp-open-doc candidate)
1182                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1183    ))
1184
1185(defvar plcmp-anything-source-completion-buffer-dabbrevs
1186  `((name . "buffer dabbrevs")
1187    (action . (("Insert" . plcmp-insert)
1188               ("Occur" .
1189                (lambda (candidate)
1190                  (funcall (plcmp-get-occur-fn)
1191                           (regexp-quote candidate)
1192                           nil)))
1193               ("Add to kill-ring" . kill-new)))
1194    (init . (lambda ()
1195              (let* ((words (plcmp-get-buffer-dabbrevs))
1196                     (words (delete plcmp-real-initial-input words)))
1197                (with-current-buffer (anything-candidate-buffer 'global)
1198                  (plcmp-insert-each-line words)))))
1199    (candidates-in-buffer)
1200    (persistent-action . (lambda (candidate)
1201                           (switch-to-buffer anything-current-buffer)
1202                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1203    ))
1204
1205
1206;; man, perldoc
1207(defvar plcmp-anything-source-doc-man-pages
1208  '((name . "perl man pages")
1209    (action . (("Show man" . woman)))
1210    (init . (lambda ()
1211              (with-current-buffer (anything-candidate-buffer 'global)
1212                (plcmp-insert-each-line plcmp-man-pages))))
1213    (candidates-in-buffer)
1214    (persistent-action . (lambda (candidate)
1215                           (woman candidate)
1216                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1217    ))
1218
1219(defvar plcmp-anything-source-doc-using-modules
1220  '((name . "using modules")
1221    (action . (("Show doc" .
1222                (lambda (candidate)
1223                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1224                    (save-selected-window
1225                      (pop-to-buffer buf)))))
1226               ("Show doc and go" .
1227                (lambda (candidate)
1228                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1229                    (switch-to-buffer buf))))
1230               ("Occur doc buffer" .
1231                (lambda (candidate)
1232                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1233                    (switch-to-buffer buf)
1234                    (call-interactively (plcmp-get-occur-fn)
1235                                        (regexp-quote candidate)))))
1236               ("Open module file" .
1237                (lambda (candidate)
1238                  (plcmp-open-module-file candidate)))
1239               ("Open module file other window" .
1240                (lambda (candidate)
1241                  (plcmp-open-module-file candidate 'pop-to-buffer)))
1242               ("Open module file other frame" .
1243                (lambda (candidate)
1244                  (plcmp-open-module-file candidate
1245                                          'switch-to-buffer-other-frame)))
1246               ("Add to kill-ring" . kill-new)))
1247    (init . (lambda ()
1248              (with-current-buffer (anything-candidate-buffer 'global)
1249                (plcmp-insert-each-line plcmp-using-modules))))
1250    (candidates-in-buffer)
1251    (persistent-action . (lambda (candidate)
1252                           (plcmp-open-doc candidate)
1253                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1254    ))
1255
1256(defvar plcmp-anything-source-doc-installed-modules
1257  '((name . "installed modules")
1258    (action . (("Show doc" .
1259                (lambda (candidate)
1260                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1261                    (save-selected-window
1262                      (pop-to-buffer buf)))))
1263               ("Show doc and go" .
1264                (lambda (candidate)
1265                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1266                    (switch-to-buffer buf))))
1267               ("Occur doc buffer" .
1268                (lambda (candidate)
1269                  (let ((buf (plcmp-get-man-buffer candidate 'module)))
1270                    (switch-to-buffer buf)
1271                    (call-interactively (plcmp-get-occur-fn)))))
1272               ("Open module file" .
1273                (lambda (candidate)
1274                  (plcmp-open-module-file candidate)))
1275               ("Open module file other window" .
1276                (lambda (candidate)
1277                  (plcmp-open-module-file candidate 'pop-to-buffer)))
1278               ("Open module file other frame" .
1279                (lambda (candidate)
1280                  (plcmp-open-module-file candidate
1281                                          'switch-to-buffer-other-frame)))
1282               ("Add to kill-ring" . kill-new)))
1283    (init . (lambda ()
1284              (with-current-buffer (anything-candidate-buffer 'global)
1285                (plcmp-insert-each-line plcmp-installed-modules))))
1286    (candidates-in-buffer)
1287    (persistent-action . (lambda (candidate)
1288                           (plcmp-open-doc candidate)
1289                           (plcmp-re-search-forward-fontify (regexp-quote candidate))))
1290    ))
1291
1292
1293;; menu
1294(defun plcmp-menu-cands ()
1295  (with-temp-buffer
1296    (let ((re (rx bol
1297                  (group (+ not-newline))
1298                  (group "plcmp-cmd-"
1299                         (+ not-newline)
1300                         eol))))
1301      (insert (substitute-command-keys (format "\\{%s}" "plcmp-mode-map")))
1302      (loop initially (goto-char (point-min))
1303            while (re-search-forward re nil t)
1304            collect (let* ((key (plcmp-trim (match-string 1)))
1305                           (command (plcmp-trim (match-string 2)))
1306                           (display (concat "[" key "] "  command))
1307                           (real command))
1308                      `(,display . ,real))))))
1309
1310(defvar plcmp-anything-source-menu
1311  `((name . "perl-completion menu")
1312    (action ("Call interactively" . (lambda (command-name)
1313                                      (call-interactively (intern command-name))))
1314            ("Add command to kill ring" . kill-new)
1315            ("Go to command's definition" . (lambda (command-name)
1316                                              (find-function
1317                                               (intern command-name)))))
1318    (candidates . plcmp-menu-cands)
1319    ))
1320
1321
1322;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323;;;; Commands
1324;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1325;; prefix: plcmp-cmd-
1326
1327;;; complete-all
1328(defvar plcmp-completion-all-static-sources
1329  '(
1330    plcmp-anything-source-completion-buffer-dabbrevs
1331    plcmp-anything-source-completion-builtin-variables
1332    plcmp-anything-source-completion-builtin-functions   
1333    plcmp-anything-source-completion-using-modules   
1334    plcmp-anything-source-completion-installed-modules
1335    ))
1336
1337(defun plcmp-get-sources-for-complete-all ()
1338  (append
1339   (plcmp-get-sources-methods plcmp-using-modules)
1340   (plcmp-get-sources-other-perl-buffers-variable)
1341   (plcmp-get-sources-other-perl-buffers-hashes)
1342   (plcmp-get-sources-other-perl-buffers-arrays)
1343   (plcmp-get-sources-other-perl-buffers-functions)
1344   plcmp-completion-all-static-sources))
1345
1346(define-plcmp-command complete-all ()
1347  (anything (plcmp-get-sources-for-complete-all) plcmp-initial-input))
1348
1349
1350;;; smart-complete
1351
1352(defvar plcmp-completion-smart-complete-static-sources
1353  '(
1354    plcmp-anything-source-completion-buffer-dabbrevs
1355    plcmp-anything-source-completion-builtin-variables
1356    plcmp-anything-source-completion-builtin-functions
1357    plcmp-anything-source-completion-using-modules
1358    plcmp-anything-source-completion-installed-modules
1359    ))
1360
1361(defun plcmp--sources-for-smart-complete ()
1362  (append
1363   (plcmp-get-sources-methods plcmp-using-modules)
1364   (plcmp-get-sources-other-perl-buffers-words)
1365   plcmp-completion-smart-complete-static-sources))
1366
1367(defsubst* plcmp-preceding-string (&optional (count 1))
1368  "現在の位置からcount文字前方位置までの文字列を返す
1369例外を出さない"
1370  (buffer-substring-no-properties
1371   (point)
1372   (condition-case nil
1373       (save-excursion (backward-char count) (point))
1374     (error (point)))))
1375
1376(defsubst plcmp-method-p ()
1377  (string-equal "->" (plcmp-preceding-string 2)))
1378
1379(defun plcmp--get-context-symbol ()
1380  "return list (context-symbol module-name-string) or list (context-symbol) if not module context.
1381context-symbol is one of the following values:
1382self
1383method
1384variable
1385array
1386hash
1387function
1388installed-module
1389otherwise
1390"
1391  (ignore-errors
1392    (save-excursion
1393      (let* ((start (point))
1394             (start-input (progn (skip-syntax-backward "w_") ;move point
1395                                 (buffer-substring-no-properties (point) start)))
1396             (obj-str (buffer-substring-no-properties ;string
1397                       (or (ignore-errors (save-excursion (forward-char -2) (point)))
1398                           (point))
1399                       (save-excursion (or (ignore-errors (backward-sexp)
1400                                                          (point))
1401                                           (point)))))
1402             (context-sym-str-list
1403              (cond
1404               ;; fullname
1405               ;; File::Copy::`!!'
1406               ((save-excursion
1407                  (goto-char start)
1408                  (skip-chars-backward "a-zA-Z0-9_")
1409                  (let ((str (plcmp-preceding-string 2)))
1410                    (when (string-equal str "::")
1411                      (backward-char 2)
1412                      (let* ((start (point))
1413                             (end (progn (skip-syntax-backward "w_")
1414                                         (point)))
1415                             (obj-str (buffer-substring-no-properties
1416                                       start
1417                                       end)))
1418                        (values 'method obj-str))))))
1419               ;; package
1420               ;; $self->`!!'
1421               ;; __PACKAGE__->`!!'
1422               ((and (plcmp-method-p)
1423                     (string-match (rx bol
1424                                       (or "$self"
1425                                           "__PACKAGE__")
1426                                       eol)
1427                                   obj-str))
1428                (list 'package))
1429               ;; method
1430               ;; Foo->`!!'
1431               ((and (plcmp-method-p)
1432                     (stringp obj-str))
1433                (list 'method obj-str))
1434               ;; variable
1435               ;; $foo`!!'
1436               ((string-equal "$" (plcmp-preceding-string 1))
1437                (list 'variable))
1438               ;; array
1439               ((string-equal "@" (plcmp-preceding-string 1))
1440                (list 'array))
1441               ;; hash
1442               ((string-equal "%" (plcmp-preceding-string 1))
1443                (list 'array))
1444               ;; function
1445               ((string-equal "&" (plcmp-preceding-string 1))
1446                (list 'function))
1447               ;; installed-module
1448               ;; use `!!'
1449               ((string-match (rx bol (* space) "use" (+ space))
1450                              (buffer-substring (point-at-bol) (point)))
1451                (list 'installed-module))
1452               (t
1453                (list 'otherwise)))))
1454        (prog1 context-sym-str-list
1455          (plcmp-log "plcmp--get-context-symbol: %s" context-sym-str-list))))))
1456
1457;; TODO
1458(defun plcmp-get-sources-for-smart-complete ()
1459  "return sources"
1460  (let* ((context-sym-str-list (plcmp--get-context-symbol))
1461         (ctx-sym (first context-sym-str-list))
1462         (module-name (second context-sym-str-list)))
1463    (let ((all-sources (plcmp--sources-for-smart-complete)))
1464      (case ctx-sym
1465        (method (let ((sources (plcmp-re-sort-sources "method"
1466                                                      all-sources)))
1467                  (if (stringp module-name)
1468                      (let ((obj (assoc-default module-name plcmp-obj-instance-of-module-maybe-alist)))
1469                        (if (and obj
1470                                 (stringp obj))
1471                            (plcmp-re-sort-sources obj sources)
1472                          (plcmp-re-sort-sources module-name sources)))
1473                    sources)))
1474        (variable (plcmp-re-sort-sources "variable"
1475                                         all-sources))
1476        (array (plcmp-re-sort-sources  "array"
1477                                       all-sources))
1478        (hash (plcmp-re-sort-sources "hash"
1479                                     all-sources))
1480        (function (plcmp-re-sort-sources "function"
1481                                         all-sources))
1482        (installed-module (plcmp-re-sort-sources "installed modules"
1483                                                 all-sources))
1484        (otherwise (let* ((sources (plcmp-re-sort-sources "method"
1485                                                         all-sources
1486                                                         t))
1487                          (sources (plcmp-re-sort-sources "dabbrev"
1488                                                          sources)))
1489                     sources))))))
1490
1491(define-plcmp-command smart-complete ()
1492  (plcmp-log "smart-complete called line: %s`!!'"
1493             (buffer-substring (point-at-bol) (point)))
1494  (anything (plcmp-get-sources-for-smart-complete) plcmp-initial-input))
1495
1496
1497;;; complete-variables
1498(defvar plcmp-completion-variable-static-sources
1499  '(
1500    plcmp-anything-source-completion-builtin-variables
1501    ))
1502
1503(defun plcmp-get-sources-for-complete-variables ()
1504  (append
1505   (plcmp-get-sources-other-perl-buffers-variable)   
1506   plcmp-completion-variable-static-sources
1507   ))
1508
1509(define-plcmp-command complete-variables ()
1510  (anything (plcmp-get-sources-for-complete-variables) plcmp-initial-input))
1511
1512;;; complete-arrays
1513(define-plcmp-command complete-arrays ()
1514  (anything (plcmp-get-sources-other-perl-buffers-arrays) plcmp-initial-input))
1515
1516;;; complete-hashes
1517(define-plcmp-command complete-hashes ()
1518  (anything (plcmp-get-sources-other-perl-buffers-hashes) plcmp-initial-input))
1519
1520;;; complete-functions
1521(defun plcmp-get-sources-for-complete-functions ()
1522  (append
1523   (list plcmp-anything-source-completion-builtin-functions)
1524   (plcmp-get-sources-other-perl-buffers-functions)
1525   (plcmp-get-sources-methods plcmp-using-modules)))
1526
1527(define-plcmp-command complete-functions ()
1528  (anything (plcmp-get-sources-for-complete-functions) plcmp-initial-input))
1529
1530;;; complete-methods
1531(define-plcmp-command complete-methods ()
1532  (anything (plcmp-get-sources-methods plcmp-using-modules) plcmp-initial-input))
1533
1534;;; complete-modules
1535(define-plcmp-command complete-modules ()
1536  (anything '(plcmp-anything-source-completion-using-modules
1537              plcmp-anything-source-completion-installed-modules)
1538            plcmp-initial-input))
1539
1540
1541;;; document
1542(defvar plcmp-show-doc-sources
1543  '(
1544    plcmp-anything-source-doc-using-modules
1545    plcmp-anything-source-doc-man-pages
1546    plcmp-anything-source-doc-installed-modules
1547    ))
1548(define-plcmp-command show-doc ()
1549  (anything plcmp-show-doc-sources))
1550
1551(define-plcmp-command show-doc-at-point ()
1552  (anything plcmp-show-doc-sources (or (thing-at-point 'symbol) "")))
1553;;; other commands
1554(defun plcmp-cmd-menu ()
1555  (interactive)
1556  (anything '(plcmp-anything-source-menu)))
1557
1558(defun plcmp-cmd-clear-all-caches ()
1559  (interactive)
1560  (dolist (variable plcmp--cached-variables)
1561    (set variable nil))
1562  (run-hooks 'plcmp-clear-all-caches-hook)
1563  (or plcmp-installed-modules
1564      (plcmp-with-set-perl5-lib
1565       (plcmp--installed-modules-asynchronously)))
1566  (message "cleared all caches and getting installed modules asynchronously"))
1567
1568;; TODO
1569(defun plcmp-cmd-show-environment ()
1570  (interactive)
1571  (require 'custom)
1572  (let* ((decode-fn (lambda (s)
1573                      (if enable-multibyte-characters
1574                          (decode-coding-string s locale-coding-system t)
1575                        s)))
1576         (buf (get-buffer-create "*perl-completion show environment*"))
1577         (customs)
1578         (commands)
1579         (plcmp-symbols (loop for sym being the symbols
1580                              for s = (symbol-name sym)
1581                              when (and (string-match "^plcmp-" s)
1582                                        (custom-variable-p sym))
1583                              collect s into custom-syms
1584                              when (string-match (concat "^" "plcmp-cmd-") s)
1585                              collect s into command-syms
1586                              finally do (setq customs custom-syms
1587                                               commands command-syms)))
1588         (perl5-lib (format "this buffer's PERL5LIB: %s\n\n"
1589                            (plcmp-with-set-perl5-lib
1590                             (require 'env)
1591                             (or (getenv "PERL5LIB") ""))))
1592         (additional-lib-directories (format "plcmp-additional-lib-directories: %S\n"
1593                                             plcmp-additional-lib-directories)))
1594    (with-current-buffer buf
1595      (erase-buffer)
1596      ;; set perl5lib
1597      (insert additional-lib-directories)
1598      (insert perl5-lib)
1599      ;; customize-variables
1600      (insert "customize-variables:\n\n")
1601      (plcmp-insert-each-line customs)
1602      (insert "\n\n")
1603      ;; commands
1604      (insert "commands:\n\n")
1605      (plcmp-insert-each-line commands)
1606      (insert "\n\n")
1607      ;; process-environment
1608      (insert "process-environment:\n\n")
1609      (loop for env in process-environment
1610            do (progn (insert (funcall decode-fn (or env "")))
1611                      (insert "\n")))
1612      (goto-char (point-min))
1613      (switch-to-buffer buf))))
1614
1615(defun plcmp-cmd-update-check ()
1616  (interactive)
1617  (when (require 'url nil t)
1618    (let* ((uri "http://svn.coderepos.org/share/lang/elisp/perl-completion/trunk/perl-completion.el")
1619           (buf (url-retrieve-synchronously uri))
1620           (re (rx "plcmp-version " (group (+ (or (any digit) "."))))))
1621      (with-current-buffer buf
1622        (goto-char (point-min))
1623        (let ((trunk-version (prog1 (when (re-search-forward re nil t)
1624                                      (string-to-number (match-string-no-properties 1)))
1625                               (kill-buffer buf))))
1626          (if (< plcmp-version trunk-version)
1627              (when (y-or-n-p "new version available. Open URL in the default browser? ")
1628                (browse-url uri))
1629            (message "%s is currently the newest version" plcmp-version)))))))
1630
1631
1632;; set-perl5lib
1633(defun plcmp-cmd-set-additional-lib-directory ()
1634  "ask directory, then set directory to `plcmp-additional-lib-directories'"
1635  (interactive)
1636  (let* ((dir (read-directory-name "set to PERL5LIB(this buffer only): " nil nil t))
1637         (dir (expand-file-name dir))
1638         (dir (directory-file-name dir)))
1639    (when (and (stringp dir)
1640               (file-exists-p dir))
1641      (add-to-list 'plcmp-additional-lib-directories dir)
1642      (message "added %s to PERL5LIB" dir))))
1643
1644;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1645;;;; Anything commands
1646;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1647;; prefix: plcmp-acmd-
1648;; plcmp-acmd -> plcmp-anything-command
1649
1650;; util
1651(defun plcmp-select-re-action (action-name-re)
1652  (let* ((actions (anything-attr 'action))
1653         (action (assoc-if (lambda (s) (string-match action-name-re s))
1654                           actions)))
1655    (if (and action
1656             (cdr action))
1657        (progn (setq anything-saved-action (cdr action))
1658               (anything-exit-minibuffer))
1659      (message "no action-name %s current source %s"
1660               action-name-re
1661               (anything-attr 'name)))))
1662
1663(defun plcmp-acmd-occur ()
1664  (interactive)
1665  (plcmp-select-re-action "^Occur"))
1666
1667(defun plcmp-acmd-show-doc ()
1668  (interactive)
1669  (plcmp-select-re-action "^show"))
1670
1671(defun plcmp-acmd-open-related-file ()
1672  (interactive)
1673  (plcmp-select-re-action "^open"))
1674
1675(defun plcmp-acmd-persistent-look ()
1676  (interactive)
1677  (anything-execute-persistent-action))
1678
1679(defun plcmp-acmd-goto-looking-point (&optional pop-to-buffer)
1680  (interactive "P")
1681  (lexical-let ((looking-point (first plcmp-look-current-positions))
1682                (buffer (second plcmp-look-current-positions))
1683                (show-fn (or pop-to-buffer 'pop-to-buffer 'switch-to-buffer)))
1684    (if (and (numberp looking-point)
1685             (bufferp buffer))
1686        (progn (setq anything-saved-action
1687                     (lambda (ignore)
1688                       (funcall show-fn buffer)
1689                       (goto-char looking-point)))
1690               (anything-exit-minibuffer))
1691      (message "not looking buffer"))))
1692
1693
1694;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695;;; Mode
1696;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697
1698(define-minor-mode perl-completion-mode "" nil " PLCompletion" plcmp-mode-map
1699  (or plcmp-installed-modules
1700      (plcmp-with-set-perl5-lib
1701       (plcmp--installed-modules-asynchronously))))
1702
1703
1704;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705;;;; Test
1706;;;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707
1708(dont-compile
1709  (when (fboundp 'expectations)
1710    (expectations
1711      (desc "plcmp-get-face-words")
1712      (expect nil
1713        (let ((b (get-buffer-create "*plcmp-test*")))
1714          (with-current-buffer b
1715            (cperl-mode)
1716            (plcmp-get-face-words))))
1717      (expect "$test"
1718        (let ((b (get-buffer-create "*plcmp-test*")))
1719          (with-current-buffer b
1720            (erase-buffer)
1721            (insert "my $test = 'hoge';\n")
1722            (cperl-mode)
1723            (font-lock-mode t)
1724            (font-lock-fontify-region (point-min) (point-max))
1725            (prog1 (car (plcmp-get-face-words))
1726              (kill-buffer b)))))
1727      (desc "plcmp--mk-module-source")
1728      (expect nil
1729        (plcmp--mk-module-source nil))
1730      (expect nil
1731        (let ((plcmp-module-methods-alist nil))
1732          (plcmp--mk-module-source "test")))
1733      (expect '((name . "module Methods") (action ("Insert" . plcmp-insert) ("Show doc" lambda (candidate) (let* ((module (plcmp-get-current-module-name)) (buf (plcmp-get-man-buffer module (quote module)))) (save-selected-window (pop-to-buffer buf)))) ("Show doc and go" lambda (candidate) (let* ((module (plcmp-get-current-module-name)) (buf (plcmp-get-man-buffer module (quote module)))) (pop-to-buffer buf))) ("Open module file" lambda (method) (let ((module (plcmp-get-current-module-name))) (plcmp-open-module-file module))) ("Open module file other window" lambda (method) (let ((module-name (plcmp-get-current-module-name))) (plcmp-open-module-file module-name (quote pop-to-buffer)))) ("Open module file other frame" lambda (candidate) (let ((module-name (plcmp-get-current-module-name))) (plcmp-open-module-file module-name (quote switch-to-buffer-other-frame)))) ("Occur module file" lambda (candidate) (let ((module-name (plcmp-get-current-module-name))) (plcmp-open-module-file module-name (quote switch-to-buffer)) (funcall (plcmp-get-occur-fn) candidate nil))) ("Add to kill-ring" . kill-new) ("Insert source name" lambda (candidate) (let ((name (plcmp-anything-get-current-source-name))) (and (stringp name) (insert name))))) (init lambda nil (with-current-buffer (anything-candidate-buffer (quote global)) (plcmp-insert-each-line (quote ("method" "method2"))))) (candidates-in-buffer) (persistent-action lambda (candidate) (let ((module-name (plcmp-get-current-module-name))) (plcmp-open-doc module-name) (plcmp-re-search-forward-fontify (regexp-quote candidate)))))
1734        (let ((plcmp-module-methods-alist '(("module" . ("method" "method2")))))
1735          (plcmp--mk-module-source "module")))
1736
1737      (desc "plcmp-tramp-p")
1738      (expect t
1739        (require 'tramp)
1740        (stub plcmp-get-current-directory => "/tramp:path/to/")
1741        (when (plcmp-tramp-p)
1742          t))
1743
1744      (desc "plcmp-sort-sources")
1745      (expect 'plcmp-anything-source-completion-builtin-variables
1746        (car (plcmp-re-sort-sources "variables" plcmp-completion-all-static-sources)))
1747
1748      (desc "plcmp--get-lib-path")
1749      (expect "~/c/test/lib"
1750        (stub file-exists-p => t)
1751        (stub plcmp-get-current-directory => "~/c/test/lib/Test/TT/Test/")
1752        (plcmp--get-lib-path))
1753      (expect "~/c/test/lib"
1754        (stub file-exists-p => t)
1755        (stub plcmp-get-current-directory => "~/c/test/lib/Test/TT/Test")
1756        (plcmp--get-lib-path))
1757      (expect "~/c/hoge/test/lib/Test/TT/Test/lib"
1758        (stub plcmp-get-current-directory => "~/c/hoge/test/lib/Test/TT/Test/lib/test")
1759        (stub file-exists-p => t)
1760        (plcmp--get-lib-path))
1761      (expect "~/c/hoge/test/lib/Test/TT/Test/lib"
1762        (stub plcmp-get-current-directory => "~/c/hoge/test/lib/Test/TT/Test/lib/test/")
1763        (stub file-exists-p => t)
1764        (plcmp--get-lib-path))
1765      (expect nil
1766        (stub plcmp-get-current-directory => "")
1767        (plcmp--get-lib-path))
1768      )))
1769
1770(provide 'perl-completion)
1771;;; perl-completion.el ends here
Note: See TracBrowser for help on using the browser.