lua-mode icon indicating copy to clipboard operation
lua-mode copied to clipboard

completion-at-point

Open ChongQing520 opened this issue 5 years ago • 0 comments

我把python-mode中的completion-at-point的代码粘贴到了lua-mode中

能做点简单的completion,没有经过测试,肯定是有bug

以下是新加的代码


(eval-and-compile
  (defconst lua-rx-constituents
    `((block-start          . ,(rx symbol-start
                                   (or "def" "class" "if" "elif" "else" "try"
                                       "except" "finally" "for" "while" "with"
                                       ;; Lua 3.5+ PEP492
                                       (and "async" (+ space)
                                            (or "def" "for" "with")))
                                   symbol-end))
      (dedenter            . ,(rx symbol-start
                                   (or "elif" "else" "except" "finally")
                                   symbol-end))
      (block-ender         . ,(rx symbol-start
                                  (or
                                   "break" "continue" "pass" "raise" "return")
                                  symbol-end))
      (decorator            . ,(rx line-start (* space) ?@ (any letter ?_)
                                   (* (any word ?_))))
      (defun                . ,(rx symbol-start
                                   (or "def" "class"
                                       ;; Lua 3.5+ PEP492
                                       (and "async" (+ space) "def"))
                                   symbol-end))
      (if-name-main         . ,(rx line-start "if" (+ space) "__name__"
                                   (+ space) "==" (+ space)
                                   (any ?' ?\") "__main__" (any ?' ?\")
                                   (* space) ?:))
      (symbol-name          . ,(rx (any letter ?_) (* (any word ?_))))
      (open-paren           . ,(rx (or "{" "[" "(")))
      (close-paren          . ,(rx (or "}" "]" ")")))
      (simple-operator      . ,(rx (any ?+ ?- ?/ ?& ?^ ?~ ?| ?* ?< ?> ?= ?%)))
      ;; FIXME: rx should support (not simple-operator).
      (not-simple-operator  . ,(rx
                                (not
                                 (any ?+ ?- ?/ ?& ?^ ?~ ?| ?* ?< ?> ?= ?%))))
      ;; FIXME: Use regexp-opt.
      (operator             . ,(rx (or "+" "-" "/" "&" "^" "~" "|" "*" "<" ">"
                                       "=" "%" "**" "//" "<<" ">>" "<=" "!="
                                       "==" ">=" "is" "not")))
      ;; FIXME: Use regexp-opt.
      (assignment-operator  . ,(rx (or "=" "+=" "-=" "*=" "/=" "//=" "%=" "**="
                                       ">>=" "<<=" "&=" "^=" "|=")))
      (string-delimiter . ,(rx (and
                                ;; Match even number of backslashes.
                                (or (not (any ?\\ ?\' ?\")) point
                                    ;; Quotes might be preceded by an escaped quote.
                                    (and (or (not (any ?\\)) point) ?\\
                                         (* ?\\ ?\\) (any ?\' ?\")))
                                (* ?\\ ?\\)
                                ;; Match single or triple quotes of any kind.
                                (group (or  "\"" "\"\"\"" "'" "'''")))))
      (coding-cookie . ,(rx line-start ?# (* space)
                            (or
                             ;; # coding=<encoding name>
                             (: "coding" (or ?: ?=) (* space) (group-n 1 (+ (or word ?-))))
                             ;; # -*- coding: <encoding name> -*-
                             (: "-*-" (* space) "coding:" (* space)
                                (group-n 1 (+ (or word ?-))) (* space) "-*-")
                             ;; # vim: set fileencoding=<encoding name> :
                             (: "vim:" (* space) "set" (+ space)
                                "fileencoding" (* space) ?= (* space)
                                (group-n 1 (+ (or word ?-))) (* space) ":")))))
    "Additional Lua specific sexps for `lua-rx'")

  (defmacro lua-rx (&rest regexps)
    "Lua mode specialized rx macro.
This variant of `rx' supports common Lua named REGEXPS."
    (let ((rx-constituents (append lua-rx-constituents rx-constituents)))
      (cond ((null regexps)
             (error "No regexp"))
            ((cdr regexps)
             (rx-to-string `(and ,@regexps) t))
            (t
             (rx-to-string (car regexps) t))))))

(defun lua-util-comint-last-prompt ()
  "Return comint last prompt overlay start and end.
This is for compatibility with Emacs < 24.4."
  (cond ((bound-and-true-p comint-last-prompt-overlay)
         (cons (overlay-start comint-last-prompt-overlay)
               (overlay-end comint-last-prompt-overlay)))
        ((bound-and-true-p comint-last-prompt)
         comint-last-prompt)
        (t nil)))

(defcustom lua-shell-completion-native-output-timeout 5.0
  "Time in seconds to wait for completion output before giving up."
  :version "25.1"
  :type 'float)


(defcustom lua-shell-completion-native-enable t
  "Enable readline based native completion."
  :version "25.1"
  :type 'boolean)

(defcustom lua-shell-prompt-pdb-regexp "[(<]*[Ii]?[Pp]db[>)]+ "
  "Regular expression matching pdb input prompt of Python shell.
It should not contain a caret (^) at the beginning."
  :type 'string)

(defvar lua-shell--block-prompt nil
  "Input block prompt for inferior lua shell.
Do not set this variable directly, instead use
`lua-shell-prompt-set-calculated-regexps'.")

(defun lua-shell-completion-get-completions (process import input)
  "Do completion at point using PROCESS for IMPORT or INPUT.
When IMPORT is non-nil takes precedence over INPUT for
completion."
  (setq input (or import input))
  (with-current-buffer (process-buffer process)
    (let ((completions
           (lua-util-strip-string
            (lua-shell-send-string-no-output
             (format
              (concat lua-shell-completion-setup-code
                      "\nprint (" lua-shell-completion-string-code ")")
              input) process))))
      (when (> (length completions) 2)
        (split-string completions
                      "^'\\|^\"\\|;\\|'$\\|\"$" t)))))

(defvar lua-shell-completion-native-redirect-buffer
  " *Lua completions redirect*"
  "Buffer to be used to redirect output of readline commands.")


(defun lua-shell-accept-process-output (process &optional timeout regexp)
  "Accept PROCESS output with TIMEOUT until REGEXP is found.
Optional argument TIMEOUT is the timeout argument to
`accept-process-output' calls.  Optional argument REGEXP
overrides the regexp to match the end of output, defaults to
`comint-prompt-regexp'.  Returns non-nil when output was
properly captured.

This utility is useful in situations where the output may be
received in chunks, since `accept-process-output' gives no
guarantees they will be grabbed in a single call.  An example use
case for this would be the CLua shell start-up, where the
banner and the initial prompt are received separately."
  (let ((regexp (or regexp comint-prompt-regexp)))
    (catch 'found
      (while t
	(when (not (accept-process-output process timeout))
          (throw 'found nil))
	
	(when (looking-back
               regexp (car (lua-util-comint-last-prompt)))
          (throw 'found t))))))

(defun lua-get-command (input)
  ;;(print input)
  (cond
   ((string-match "\\." input)
    (let ((words (split-string input "\\.")))
      (format "for i in pairs(%s) do if string.find(i,\"%s\") then print(\"%s.\" .. i) end end\n"
	      (nth 0 words)
	      (nth 1 words)
	      (nth 0 words))))
   ((string-match ":" input)
    (let ((words (split-string input ":")))
      (format "for i in pairs(%s) do if string.find(i,\"%s\") then print(\"%s:\"i) end end\n"
	      (nth 0 words)
	      (nth 1 words)
	      (nth 0 words))))
   (t (format "for i in pairs(_G) do if string.find(i,\"%s\") then print(i) end end\n" input))
   ))

(defun lua-shell-completion-native-get-completions (process import input)
  "Get completions using native readline for PROCESS.
When IMPORT is non-nil takes precedence over INPUT for
completion."
  (with-current-buffer (process-buffer process)
    (let* ((input (or import input))
           (original-filter-fn (process-filter process))
           (redirect-buffer (get-buffer-create
                             lua-shell-completion-native-redirect-buffer))
           ;;(command "for i in pairs(_G) do if string.find(i,\"%s\") then print(i) end end\n" )
           (input-to-send (lua-get-command input))
	   )
      ;; Ensure restoring the process filter, even if the user quits
      ;; or there's some other error.
      (unwind-protect
          (with-current-buffer redirect-buffer
            ;; Cleanup the redirect buffer
            (erase-buffer)
            ;; Mimic `comint-redirect-send-command', unfortunately it
            ;; can't be used here because it expects a newline in the
            ;; command and that's exactly what we are trying to avoid.
            (let ((comint-redirect-echo-input nil)
                  (comint-redirect-completed nil)
                  (comint-redirect-perform-sanity-check nil)
                  (comint-redirect-insert-matching-regexp t)
                  (comint-redirect-finished-regexp
                   "> ")
                  (comint-redirect-output-buffer redirect-buffer))
              ;; Compatibility with Emacs 24.x.  Comint changed and
              ;; now `comint-redirect-filter' gets 3 args.  This
              ;; checks which version of `comint-redirect-filter' is
              ;; in use based on its args and uses `apply-partially'
              ;; to make it up for the 3 args case.
              (if (= (length
                      (help-function-arglist 'comint-redirect-filter)) 3)
                  (set-process-filter
                   process (apply-partially
                            #'comint-redirect-filter original-filter-fn))
                (set-process-filter process #'comint-redirect-filter))
              (process-send-string process input-to-send)
              ;; Grab output until our dummy completion used as
              ;; output end marker is found.
              (when (lua-shell-accept-process-output
                     process lua-shell-completion-native-output-timeout
                     comint-redirect-finished-regexp)
                (cl-remove-duplicates

		 (split-string
                  (buffer-substring-no-properties
                   (line-beginning-position) (point-min))
                  "[ \f\t\n\r\v()]+" t)
		 
                 :test #'string=))))
        (set-process-filter process original-filter-fn)))))

(defun lua-shell-completion-at-point (&optional process)
  "Function for `completion-at-point-functions' in `inferior-lua-mode'.
Optional argument PROCESS forces completions to be retrieved
using that one instead of current buffer's process."
  (setq process (or process (get-buffer-process (current-buffer))))
  (let* ((line-start (if (derived-mode-p 'inferior-lua-mode)
                         ;; Working on a shell buffer: use prompt end.
                         (cdr (lua-util-comint-last-prompt))
                       (line-beginning-position)))
	 
         (import-statement
          (when (string-match-p
                 (rx (* space) word-start (or "require") word-end space)
                 (buffer-substring-no-properties line-start (point)))
            (buffer-substring-no-properties line-start (point))))

         (start
          (save-excursion
            (if (not (re-search-backward
                      (lua-rx   ;; find the current-word
                       (or whitespace open-paren close-paren string-delimiter))
                      line-start
                      t 1))
                line-start
              (forward-char (length (match-string-no-properties 0)))
              (point))))
         (end (point))

         (prompt-boundaries
          (with-current-buffer (process-buffer process)
            (lua-util-comint-last-prompt)))

         (prompt
          (with-current-buffer (process-buffer process)
            (when prompt-boundaries
              (buffer-substring-no-properties
               (car prompt-boundaries) (cdr prompt-boundaries)))))
         (completion-fn
          (with-current-buffer (process-buffer process)
            (cond ((or (null prompt)
                       (< (point) (cdr prompt-boundaries)))
                   #'ignore)
                  ((or (not lua-shell-completion-native-enable)
                       ;; Even if native completion is enabled, for
                       ;; pdb interaction always use the fallback
                       ;; mechanism since the completer is changed.
                       ;; Also, since pdb interaction is single-line
                       ;; based, this is enough.
                       (string-match-p lua-shell-prompt-pdb-regexp prompt)
		       )
                   (if (or (equal lua-shell--block-prompt prompt)
                           (string-match-p
                            lua-shell-prompt-block-regexp prompt))
                       ;; The non-native completion mechanism sends
                       ;; newlines to the interpreter, so we can't use
                       ;; it during a multiline statement (Bug#28051).
                       #'ignore
                     #'lua-shell-completion-get-completions))
                  (t
		   #'lua-shell-completion-native-get-completions)))))
    (list start end
          (completion-table-dynamic
           (apply-partially
            completion-fn
            process import-statement)))))

以下是更新的代码


;;;###autoload
(defun lua-start-process (&optional name program startfile &rest switches)
  "Start a Lua process named NAME, running PROGRAM.
PROGRAM defaults to NAME, which defaults to `lua-default-application'.
When called interactively, switch to the process buffer."
  (interactive)
  (or switches
      (setq switches lua-default-command-switches))
  (setq name (or name (if (consp lua-default-application)
                          (car lua-default-application)
                        lua-default-application)))
  (setq program (or program lua-default-application))
  (setq lua-process-buffer (apply 'make-comint name program startfile switches))
  (setq lua-process (get-buffer-process lua-process-buffer))
  (set-process-query-on-exit-flag lua-process nil)
  (with-current-buffer lua-process-buffer
    ;; wait for prompt
    (while (not (lua-prompt-line))
      (accept-process-output (get-buffer-process (current-buffer)))
      (goto-char (point-max)))
    ;; send initialization code
    (lua-send-string lua-process-init-code)
    (add-hook 'completion-at-point-functions
              #'lua-shell-completion-at-point nil 'local)

    ;; enable error highlighting in stack traces
    (require 'compile)
    (setq lua--repl-buffer-p t)
    (make-local-variable 'compilation-error-regexp-alist)
    (setq compilation-error-regexp-alist
          (cons (list lua-traceback-line-re 1 2)
                compilation-error-regexp-alist))
    (compilation-shell-minor-mode 1))

  ;; when called interactively, switch to process buffer
  (if (called-interactively-p 'any)
      (switch-to-buffer lua-process-buffer)))

ChongQing520 avatar Mar 27 '19 00:03 ChongQing520