| | 46 | |
| | 47 | (defcustom plcmp-lib-directory-re "lib/" |
| | 48 | "regexp, used in `plcmp--get-lib-path' to get library path. |
| | 49 | eg, when directory of buffer is \"~/someproject/lib/hoge.pm\" and this value is \"lib/\" |
| | 50 | set \"~/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 | |
| | 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 | |
| 244 | | (sorted-sources (loop for source in sources |
| 245 | | if (plcmp--re-match-sources1 regexps source) |
| 246 | | collect source into match-sources |
| 247 | | else |
| 248 | | collect source into unmatch-sources |
| 249 | | finally return (if reverse |
| 250 | | (nconc unmatch-sources match-sources) |
| 251 | | (nconc match-sources unmatch-sources))))) |
| 252 | | (prog1 sorted-sources |
| 253 | | (plcmp-log "plcmp-re-sort-sources: %s" sorted-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) |
| 378 | | (message "fetching installed modules...") |
| 379 | | (let* ((command "find") |
| 380 | | (args (concat "`perl -e 'pop @INC; print join(q{ }, @INC);'`" |
| 381 | | " -name '*.pm' -type f " |
| 382 | | "| xargs grep -E -h -o 'package [a-zA-Z0-9:]+;' " |
| 383 | | "| perl -nle 's/package\s+(.+);/$1/; print' " |
| 384 | | "| sort " |
| 385 | | "| uniq ")) |
| 386 | | (proc (start-process-shell-command "installed perl modules" |
| 387 | | plcmp-installed-modules-buffer-name |
| 388 | | command |
| 389 | | args))) |
| 390 | | (set-process-sentinel proc 'plcmp--installed-modules-set-cache) |
| 391 | | ;; return process |
| 392 | | proc)) |
| | 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))) |
| 414 | | (let ((re (rx-to-string `(and bol |
| 415 | | (* space) |
| 416 | | "use" |
| 417 | | (+ space) |
| 418 | | (group ;1 package |
| 419 | | (regexp ,plcmp-perl-package-re)) |
| 420 | | (* not-newline) |
| 421 | | ";")))) |
| 422 | | (plcmp-collect-matches re 1 'match-string-no-properties))) |
| | 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))) |
| 576 | | (let ((ret)) |
| 577 | | (maphash (lambda (k v) (push k ret)) hash) ; remove-dups |
| 578 | | ret)))) |
| 579 | | |
| 580 | | (defvar plcmp-current-buffer-words-alist nil |
| 581 | | "alist, ((variable . (list of variables)) |
| 582 | | (array . (list of arrays)) |
| 583 | | (hash . (list of hashes)) |
| 584 | | (functions . (list of functions)))") |
| 585 | | (add-hook 'plcmp--command-cleanup-hook |
| 586 | | (lambda () |
| 587 | | (setq plcmp-current-buffer-words-alist nil))) |
| 588 | | |
| 589 | | |
| 590 | | (defun plcmp-get-current-buffer-words-alist () |
| 591 | | (or plcmp-current-buffer-words-alist |
| 592 | | (let ((variables (plcmp-get-face-words '(font-lock-variable-name-face))) |
| 593 | | (arrays (plcmp-get-face-words '(cperl-array-face))) |
| 594 | | (hashes (plcmp-get-face-words '(cperl-hash-face))) |
| 595 | | (functions (plcmp-get-buffer-subs))) |
| 596 | | (setq plcmp-current-buffer-words-alist |
| 597 | | `((variable . ,variables) |
| 598 | | (array . ,arrays) |
| 599 | | (hash . ,hashes) |
| 600 | | (function . ,functions)))))) |
| 601 | | |
| 602 | | (defun plcmp-get-current-buffer-variables () |
| 603 | | (let ((alist (plcmp-get-current-buffer-words-alist))) |
| 604 | | (prog1 (assoc-default 'variable alist 'eq) |
| 605 | | (plcmp-log "getting current buffer variables")))) |
| 606 | | |
| 607 | | (defvar plcmp-anything-source-completion-current-buffer-variables |
| 608 | | `((name . "buffer variables") |
| 609 | | (type . plcmp-completion) |
| 610 | | (init . (lambda () |
| 611 | | (let ((words (plcmp-get-current-buffer-variables))) |
| 612 | | (with-current-buffer (anything-candidate-buffer 'global) |
| 613 | | (plcmp-insert-each-line words))))) |
| 614 | | (candidates-in-buffer))) |
| 615 | | |
| 616 | | (defun plcmp-get-current-buffer-arrays () |
| 617 | | (let ((alist (plcmp-get-current-buffer-words-alist))) |
| 618 | | (prog1 (assoc-default 'array alist 'eq) |
| 619 | | (plcmp-log "getting current buffer arrays")))) |
| 620 | | |
| 621 | | (defvar plcmp-anything-source-completion-current-buffer-arrays |
| 622 | | `((name . "buffer arrays") |
| 623 | | (type . plcmp-completion) |
| 624 | | (init . (lambda () |
| 625 | | (let ((words (plcmp-get-current-buffer-arrays))) |
| 626 | | (with-current-buffer (anything-candidate-buffer 'global) |
| 627 | | (plcmp-insert-each-line words))))) |
| 628 | | (candidates-in-buffer))) |
| 629 | | |
| 630 | | (defun plcmp-get-current-buffer-hashes () |
| 631 | | (let ((alist (plcmp-get-current-buffer-words-alist))) |
| 632 | | (prog1 (assoc-default 'hash alist 'eq) |
| 633 | | (plcmp-log "getting current buffer hashes")))) |
| 634 | | |
| 635 | | (defvar plcmp-anything-source-completion-current-buffer-hashes |
| 636 | | `((name . "buffer hashes") |
| 637 | | (type . plcmp-completion) |
| 638 | | (init . (lambda () |
| 639 | | (let ((words (plcmp-get-current-buffer-hashes))) |
| 640 | | (with-current-buffer (anything-candidate-buffer 'global) |
| 641 | | (plcmp-insert-each-line words))))) |
| 642 | | (candidates-in-buffer))) |
| 643 | | |
| 644 | | (defun plcmp-get-current-buffer-functions () |
| 645 | | (let ((alist (plcmp-get-current-buffer-words-alist))) |
| 646 | | (prog1 (assoc-default 'function alist 'eq) |
| 647 | | (plcmp-log "getting current buffer functions")))) |
| 648 | | |
| 649 | | (defvar plcmp-anything-source-completion-current-buffer-functions |
| 650 | | `((name . "buffer functions") |
| 651 | | (type . plcmp-completion) |
| 652 | | (init . (lambda () |
| 653 | | (let ((words (plcmp-get-current-buffer-functions))) |
| 654 | | (with-current-buffer (anything-candidate-buffer 'global) |
| 655 | | (plcmp-insert-each-line words))))) |
| 656 | | (candidates-in-buffer))) |
| 657 | | |
| | 646 | (maphash (lambda (k v) (push k ret)) hash) ; remove-dups |
| | 647 | (nreverse ret)))) |
| 671 | | (defun plcmp-get-other-perl-buffers-words () |
| 672 | | (let* ((perl-buffers (remove-if-not (lambda (buf) |
| 673 | | (string-match plcmp-perl-buffer-re (buffer-name buf))) |
| 674 | | (buffer-list))) |
| 675 | | (perl-buffers (subseq perl-buffers 0 plcmp-other-perl-buffer-limit-number))) |
| 676 | | (prog1 (loop for buffer in perl-buffers |
| 677 | | when (bufferp buffer) |
| 678 | | nconc (with-current-buffer buffer |
| 679 | | (plcmp-get-face-words plcmp-other-perl-buffers-words-faces))) |
| 680 | | (plcmp-log "length of other perl-buffers: %s" (length perl-buffers))))) |
| 681 | | |
| | 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))) |