few improvements
This commit is contained in:
parent
a74ef8701b
commit
e1a272744a
|
@ -1 +1,24 @@
|
|||
(nil)
|
||||
((("Settings" .
|
||||
[0 0 0 0 0 0 0 1])
|
||||
("emacs-lisp" .
|
||||
[1 0 0 2 0 1 0 0 0 0])
|
||||
("name" .
|
||||
[1 0 0 0])
|
||||
("random" .
|
||||
[0 0 0 1 0 0])
|
||||
("import" .
|
||||
[0 0 0 0 1 1])
|
||||
("print" .
|
||||
[0 0 1 0 0])
|
||||
("lsh" .
|
||||
[0 0 1])
|
||||
("alpha" .
|
||||
[0 0 1 2 0])
|
||||
("num" .
|
||||
[3 0 1])
|
||||
("both" .
|
||||
[1 0 0 0])
|
||||
("sort" .
|
||||
[1 0 0 0])
|
||||
("reversed" .
|
||||
[0 0 0 1 0 0 0 0])))
|
||||
|
|
72
config.el
72
config.el
|
@ -1,15 +1,18 @@
|
|||
(setq user-full-name "Abraham Raji")
|
||||
(setq user-mail-address "abrahamraji99@gmail.com")
|
||||
|
||||
(setq inhibit-startup-message t)
|
||||
;; ido mode
|
||||
(setq indo-enable-flex-matching t)
|
||||
(setq ido-eveywhere t)
|
||||
(ido-mode 1);;ido end
|
||||
(defalias 'list-buffers 'ibuffer);;ibuffer
|
||||
(defalias 'list-buffers 'ibuffer)
|
||||
(tool-bar-mode -1)
|
||||
(windmove-default-keybindings)
|
||||
(global-linum-mode t)
|
||||
;;Menubar
|
||||
(allout-mode) ;;outlining
|
||||
(global-font-lock-mode 1) ;;syntax highlighting
|
||||
|
||||
(setq indo-enable-flex-matching t)
|
||||
(setq ido-eveywhere t)
|
||||
(ido-mode 1)
|
||||
|
||||
(menu-bar-mode -1)
|
||||
(defun my-menu-bar-open-after ()
|
||||
(remove-hook 'pre-command-hook 'my-menu-bar-open-after)
|
||||
|
@ -26,12 +29,41 @@
|
|||
(add-hook 'pre-command-hook 'my-menu-bar-open-after))))
|
||||
(global-set-key [f10] 'my-menu-bar-open)
|
||||
|
||||
(add-to-list 'default-frame-alist
|
||||
'(font . "DejaVu Sans Mono-10"))
|
||||
|
||||
(ac-config-default)
|
||||
(global-auto-complete-mode t)
|
||||
(add-to-list 'ac-modes 'org-mode)
|
||||
|
||||
(use-package flycheck
|
||||
:ensure t
|
||||
:init
|
||||
(global-flycheck-mode t))
|
||||
|
||||
(use-package htmlize
|
||||
:ensure t)
|
||||
|
||||
(use-package liso-theme
|
||||
:ensure t
|
||||
:config (load-theme 'liso t))
|
||||
|
||||
(add-to-list 'load-path "/home/guyfawkes/.emacs.d/matlab-emacs-master")
|
||||
(load-library "matlab-load")
|
||||
|
||||
(unless (file-expand-wildcards (concat package-user-dir "/org-[0-9]*"))
|
||||
(package-install (elt (cdr (assoc 'org package-archive-contents)) 0)))
|
||||
(require 'org)
|
||||
|
||||
(add-to-list 'load-path "/home/guyfawkes/.emacs.d/matlab-emacs-master")
|
||||
(load-library "matlab-load")
|
||||
(use-package org-bullets
|
||||
:ensure t
|
||||
:config
|
||||
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
|
||||
|
||||
(add-to-list 'load-path "~/.emacs.d/org-reveal")
|
||||
(require 'ox-reveal)
|
||||
(setq org-reveal-root "http://cdn.jsdelivr.net/reveal.js/3.0.0/")
|
||||
(setq org-reveal-mathjax t)
|
||||
|
||||
(use-package try
|
||||
:ensure t)
|
||||
|
@ -41,25 +73,7 @@
|
|||
:config
|
||||
(which-key-mode))
|
||||
|
||||
(add-to-list 'load-path "~/.emacs.d/org-reveal")
|
||||
(require 'ox-reveal)
|
||||
(setq org-reveal-root "http://cdn.jsdelivr.net/reveal.js/3.0.0/")
|
||||
(setq org-reveal-mathjax t)
|
||||
|
||||
(use-package htmlize
|
||||
:ensure t)
|
||||
|
||||
(require 'package)
|
||||
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
|
||||
(package-initialize) ;load and activate packages, including auto-complete
|
||||
(ac-config-default)
|
||||
(global-auto-complete-mode t)
|
||||
|
||||
(use-package org-bullets
|
||||
:ensure t
|
||||
:config
|
||||
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
|
||||
|
||||
(use-package liso-theme
|
||||
(use-package elpy
|
||||
:ensure t
|
||||
:config (load-theme 'liso t))
|
||||
:config
|
||||
(elpy-enable))
|
||||
|
|
138
config.org
138
config.org
|
@ -1,17 +1,28 @@
|
|||
Personal Settings
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
* Personal Settings
|
||||
** My Info
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq user-full-name "Abraham Raji")
|
||||
(setq user-mail-address "abrahamraji99@gmail.com")
|
||||
(setq inhibit-startup-message t)
|
||||
;; ido mode
|
||||
(setq user-mail-address "abrahamraji99@gmail.com")
|
||||
#+END_SRC
|
||||
** One-line Settings
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq inhibit-startup-message t)
|
||||
(defalias 'list-buffers 'ibuffer)
|
||||
(tool-bar-mode -1)
|
||||
(windmove-default-keybindings)
|
||||
(global-linum-mode t)
|
||||
(allout-mode) ;;outlining
|
||||
(global-font-lock-mode 1) ;;syntax highlighting
|
||||
#+END_SRC
|
||||
** ido mode
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq indo-enable-flex-matching t)
|
||||
(setq ido-eveywhere t)
|
||||
(ido-mode 1);;ido end
|
||||
(defalias 'list-buffers 'ibuffer);;ibuffer
|
||||
(tool-bar-mode -1)
|
||||
(windmove-default-keybindings)
|
||||
(global-linum-mode t)
|
||||
;;Menubar
|
||||
(ido-mode 1)
|
||||
#+END_SRC
|
||||
|
||||
** Menubar
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(menu-bar-mode -1)
|
||||
(defun my-menu-bar-open-after ()
|
||||
(remove-hook 'pre-command-hook 'my-menu-bar-open-after)
|
||||
|
@ -27,8 +38,56 @@ Personal Settings
|
|||
(setq menu-bar-mode 42)
|
||||
(add-hook 'pre-command-hook 'my-menu-bar-open-after))))
|
||||
(global-set-key [f10] 'my-menu-bar-open)
|
||||
#+END_SRC
|
||||
#+END_SRC
|
||||
** Font
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-to-list 'default-frame-alist
|
||||
'(font . "DejaVu Sans Mono-10"))
|
||||
#+END_SRC
|
||||
** Babel in org-mode
|
||||
#+BEGIN_SRC
|
||||
; And add babel inline code execution
|
||||
; babel, for executing code in org-mode.
|
||||
(org-babel-do-load-languages
|
||||
'org-babel-load-languages
|
||||
; load all language marked with (lang . t).
|
||||
'((C . t)
|
||||
(css . t)
|
||||
(emacs-lisp . t)
|
||||
(js . t)
|
||||
(python . t)
|
||||
#+END_SRC
|
||||
* Packages
|
||||
** auto-complete
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(ac-config-default)
|
||||
(global-auto-complete-mode t)
|
||||
(add-to-list 'ac-modes 'org-mode)
|
||||
#+END_SRC
|
||||
** flycheck
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package flycheck
|
||||
:ensure t
|
||||
:init
|
||||
(global-flycheck-mode t))
|
||||
#+END_SRC
|
||||
** htmlize
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package htmlize
|
||||
:ensure t)
|
||||
#+END_SRC
|
||||
** liso-theme
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package liso-theme
|
||||
:ensure t
|
||||
:config (load-theme 'liso t))
|
||||
#+END_SRC
|
||||
|
||||
** matlab
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-to-list 'load-path "/home/guyfawkes/.emacs.d/matlab-emacs-master")
|
||||
(load-library "matlab-load")
|
||||
#+END_SRC
|
||||
** org
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(unless (file-expand-wildcards (concat package-user-dir "/org-[0-9]*"))
|
||||
|
@ -36,10 +95,20 @@ Personal Settings
|
|||
(require 'org)
|
||||
#+END_SRC
|
||||
|
||||
** matlab
|
||||
** org-mode Bullets
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-to-list 'load-path "/home/guyfawkes/.emacs.d/matlab-emacs-master")
|
||||
(load-library "matlab-load")
|
||||
(use-package org-bullets
|
||||
:ensure t
|
||||
:config
|
||||
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
|
||||
#+END_SRC
|
||||
|
||||
** ox-reveal
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-to-list 'load-path "~/.emacs.d/org-reveal")
|
||||
(require 'ox-reveal)
|
||||
(setq org-reveal-root "http://cdn.jsdelivr.net/reveal.js/3.0.0/")
|
||||
(setq org-reveal-mathjax t)
|
||||
#+END_SRC
|
||||
** try package
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
|
@ -54,39 +123,10 @@ Personal Settings
|
|||
:config
|
||||
(which-key-mode))
|
||||
#+END_SRC
|
||||
|
||||
** ox-reveal
|
||||
** elpy
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-to-list 'load-path "~/.emacs.d/org-reveal")
|
||||
(require 'ox-reveal)
|
||||
(setq org-reveal-root "http://cdn.jsdelivr.net/reveal.js/3.0.0/")
|
||||
(setq org-reveal-mathjax t)
|
||||
#+END_SRC
|
||||
** htmlize
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package htmlize
|
||||
:ensure t)
|
||||
#+END_SRC
|
||||
|
||||
** auto-complete
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(require 'package)
|
||||
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
|
||||
(package-initialize) ;load and activate packages, including auto-complete
|
||||
(ac-config-default)
|
||||
(global-auto-complete-mode t)
|
||||
#+END_SRC
|
||||
|
||||
** org-mode Bullets
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package org-bullets
|
||||
:ensure t
|
||||
:config
|
||||
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
|
||||
#+END_SRC
|
||||
** liso-theme
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package liso-theme
|
||||
:ensure t
|
||||
:config (load-theme 'liso t))
|
||||
(use-package elpy
|
||||
:ensure t
|
||||
:config
|
||||
(elpy-enable))
|
||||
#+END_SRC
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,50 @@
|
|||
;;; company-abbrev.el --- company-mode completion backend for abbrev
|
||||
|
||||
;; Copyright (C) 2009-2011, 2015 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
(require 'abbrev)
|
||||
|
||||
(defun company-abbrev-insert (match)
|
||||
"Replace MATCH with the expanded abbrev."
|
||||
(expand-abbrev))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-abbrev (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for abbrev."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-abbrev
|
||||
'company-abbrev-insert))
|
||||
(prefix (company-grab-symbol))
|
||||
(candidates (nconc
|
||||
(delete "" (all-completions arg global-abbrev-table))
|
||||
(delete "" (all-completions arg local-abbrev-table))))
|
||||
(meta (abbrev-expansion arg))))
|
||||
|
||||
(provide 'company-abbrev)
|
||||
;;; company-abbrev.el ends here
|
Binary file not shown.
|
@ -0,0 +1,383 @@
|
|||
;;; company-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'load-path (directory-file-name
|
||||
(or (file-name-directory #$) (car load-path))))
|
||||
|
||||
|
||||
;;;### (autoloads nil "company" "company.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company.el
|
||||
|
||||
(autoload 'company-mode "company" "\
|
||||
\"complete anything\"; is an in-buffer completion framework.
|
||||
Completion starts automatically, depending on the values
|
||||
`company-idle-delay' and `company-minimum-prefix-length'.
|
||||
|
||||
Completion can be controlled with the commands:
|
||||
`company-complete-common', `company-complete-selection', `company-complete',
|
||||
`company-select-next', `company-select-previous'. If these commands are
|
||||
called before `company-idle-delay', completion will also start.
|
||||
|
||||
Completions can be searched with `company-search-candidates' or
|
||||
`company-filter-candidates'. These can be used while completion is
|
||||
inactive, as well.
|
||||
|
||||
The completion data is retrieved using `company-backends' and displayed
|
||||
using `company-frontends'. If you want to start a specific backend, call
|
||||
it interactively or use `company-begin-backend'.
|
||||
|
||||
By default, the completions list is sorted alphabetically, unless the
|
||||
backend chooses otherwise, or `company-transformers' changes it later.
|
||||
|
||||
regular keymap (`company-mode-map'):
|
||||
|
||||
\\{company-mode-map}
|
||||
keymap during active completions (`company-active-map'):
|
||||
|
||||
\\{company-active-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(defvar global-company-mode nil "\
|
||||
Non-nil if Global Company mode is enabled.
|
||||
See the `global-company-mode' command
|
||||
for a description of this minor mode.
|
||||
Setting this variable directly does not take effect;
|
||||
either customize it (see the info node `Easy Customization')
|
||||
or call the function `global-company-mode'.")
|
||||
|
||||
(custom-autoload 'global-company-mode "company" nil)
|
||||
|
||||
(autoload 'global-company-mode "company" "\
|
||||
Toggle Company mode in all buffers.
|
||||
With prefix ARG, enable Global Company mode if ARG is positive;
|
||||
otherwise, disable it. If called from Lisp, enable the mode if
|
||||
ARG is omitted or nil.
|
||||
|
||||
Company mode is enabled in all buffers where
|
||||
`company-mode-on' would do it.
|
||||
See `company-mode' for more information on Company mode.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'company-manual-begin "company" "\
|
||||
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(autoload 'company-complete "company" "\
|
||||
Insert the common part of all candidates or the current selection.
|
||||
The first time this is called, the common part is inserted, the second
|
||||
time, or when the selection has been changed, the selected candidate is
|
||||
inserted.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company" '("company-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-abbrev" "company-abbrev.el" (0 0 0
|
||||
;;;;;; 0))
|
||||
;;; Generated autoloads from company-abbrev.el
|
||||
|
||||
(autoload 'company-abbrev "company-abbrev" "\
|
||||
`company-mode' completion backend for abbrev.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-abbrev" '("company-abbrev-insert")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-bbdb" "company-bbdb.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-bbdb.el
|
||||
|
||||
(autoload 'company-bbdb "company-bbdb" "\
|
||||
`company-mode' completion backend for BBDB.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORE)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-bbdb" '("company-bbdb-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-capf" "company-capf.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-capf.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-capf" '("company-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-clang" "company-clang.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-clang.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-clang" '("company-clang")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-cmake" "company-cmake.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-cmake.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-cmake" '("company-cmake")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-css" "company-css.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-css.el
|
||||
|
||||
(autoload 'company-css "company-css" "\
|
||||
`company-mode' completion backend for `css-mode'.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-css" '("company-css-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-dabbrev" "company-dabbrev.el" (0 0
|
||||
;;;;;; 0 0))
|
||||
;;; Generated autoloads from company-dabbrev.el
|
||||
|
||||
(autoload 'company-dabbrev "company-dabbrev" "\
|
||||
dabbrev-like `company-mode' completion backend.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-dabbrev" '("company-dabbrev-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-dabbrev-code" "company-dabbrev-code.el"
|
||||
;;;;;; (0 0 0 0))
|
||||
;;; Generated autoloads from company-dabbrev-code.el
|
||||
|
||||
(autoload 'company-dabbrev-code "company-dabbrev-code" "\
|
||||
dabbrev-like `company-mode' backend for code.
|
||||
The backend looks for all symbols in the current buffer that aren't in
|
||||
comments or strings.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-dabbrev-code" '("company-dabbrev-code-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-eclim" "company-eclim.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-eclim.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-eclim" '("company-eclim")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-elisp" "company-elisp.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-elisp.el
|
||||
|
||||
(autoload 'company-elisp "company-elisp" "\
|
||||
`company-mode' completion backend for Emacs Lisp.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-elisp" '("company-elisp-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-etags" "company-etags.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-etags.el
|
||||
|
||||
(autoload 'company-etags "company-etags" "\
|
||||
`company-mode' completion backend for etags.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-etags" '("company-etags-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-files" "company-files.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-files.el
|
||||
|
||||
(autoload 'company-files "company-files" "\
|
||||
`company-mode' completion backend existing file names.
|
||||
Completions works for proper absolute and relative files paths.
|
||||
File paths with spaces are only supported inside strings.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-files" '("company-file")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-gtags" "company-gtags.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-gtags.el
|
||||
|
||||
(autoload 'company-gtags "company-gtags" "\
|
||||
`company-mode' completion backend for GNU Global.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-gtags" '("company-gtags-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-ispell" "company-ispell.el" (0 0 0
|
||||
;;;;;; 0))
|
||||
;;; Generated autoloads from company-ispell.el
|
||||
|
||||
(autoload 'company-ispell "company-ispell" "\
|
||||
`company-mode' completion backend using Ispell.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-ispell" '("company-ispell-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-keywords" "company-keywords.el" (0
|
||||
;;;;;; 0 0 0))
|
||||
;;; Generated autoloads from company-keywords.el
|
||||
|
||||
(autoload 'company-keywords "company-keywords" "\
|
||||
`company-mode' backend for programming language keywords.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-keywords" '("company-keywords-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-nxml" "company-nxml.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-nxml.el
|
||||
|
||||
(autoload 'company-nxml "company-nxml" "\
|
||||
`company-mode' completion backend for `nxml-mode'.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-nxml" '("company-nxml-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-oddmuse" "company-oddmuse.el" (0 0
|
||||
;;;;;; 0 0))
|
||||
;;; Generated autoloads from company-oddmuse.el
|
||||
|
||||
(autoload 'company-oddmuse "company-oddmuse" "\
|
||||
`company-mode' completion backend for `oddmuse-mode'.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-oddmuse" '("company-oddmuse-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-semantic" "company-semantic.el" (0
|
||||
;;;;;; 0 0 0))
|
||||
;;; Generated autoloads from company-semantic.el
|
||||
|
||||
(autoload 'company-semantic "company-semantic" "\
|
||||
`company-mode' completion backend using CEDET Semantic.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-semantic" '("company-semantic-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-template" "company-template.el" (0
|
||||
;;;;;; 0 0 0))
|
||||
;;; Generated autoloads from company-template.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-template" '("company-template-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-tempo" "company-tempo.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-tempo.el
|
||||
|
||||
(autoload 'company-tempo "company-tempo" "\
|
||||
`company-mode' completion backend for tempo.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-tempo" '("company-tempo-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-tng" "company-tng.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-tng.el
|
||||
|
||||
(autoload 'company-tng-frontend "company-tng" "\
|
||||
When the user changes the selection at least once, this
|
||||
frontend will display the candidate in the buffer as if it's
|
||||
already there and any key outside of `company-active-map' will
|
||||
confirm the selection and finish the completion.
|
||||
|
||||
\(fn COMMAND)" nil nil)
|
||||
|
||||
(autoload 'company-tng-configure-default "company-tng" "\
|
||||
Applies the default configuration to enable company-tng.
|
||||
|
||||
\(fn)" nil nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-tng" '("company-tng--")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-xcode" "company-xcode.el" (0 0 0 0))
|
||||
;;; Generated autoloads from company-xcode.el
|
||||
|
||||
(autoload 'company-xcode "company-xcode" "\
|
||||
`company-mode' completion backend for Xcode projects.
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-xcode" '("company-xcode-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "company-yasnippet" "company-yasnippet.el"
|
||||
;;;;;; (0 0 0 0))
|
||||
;;; Generated autoloads from company-yasnippet.el
|
||||
|
||||
(autoload 'company-yasnippet "company-yasnippet" "\
|
||||
`company-mode' backend for `yasnippet'.
|
||||
|
||||
This backend should be used with care, because as long as there are
|
||||
snippets defined for the current major mode, this backend will always
|
||||
shadow backends that come after it. Recommended usages:
|
||||
|
||||
* In a buffer-local value of `company-backends', grouped with a backend or
|
||||
several that provide actual text completions.
|
||||
|
||||
(add-hook 'js-mode-hook
|
||||
(lambda ()
|
||||
(set (make-local-variable 'company-backends)
|
||||
'((company-dabbrev-code company-yasnippet)))))
|
||||
|
||||
* After keyword `:with', grouped with other backends.
|
||||
|
||||
(push '(company-semantic :with company-yasnippet) company-backends)
|
||||
|
||||
* Not in `company-backends', just bound to a key.
|
||||
|
||||
(global-set-key (kbd \"C-c y\") 'company-yasnippet)
|
||||
|
||||
\(fn COMMAND &optional ARG &rest IGNORE)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-yasnippet" '("company-yasnippet--")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil nil ("company-pkg.el") (0 0 0 0))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
;;; company-autoloads.el ends here
|
|
@ -0,0 +1,61 @@
|
|||
;;; company-bbdb.el --- company-mode completion backend for BBDB in message-mode
|
||||
|
||||
;; Copyright (C) 2013-2014, 2016 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Jan Tatarik <jan.tatarik@gmail.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(declare-function bbdb-record-get-field "bbdb")
|
||||
(declare-function bbdb-records "bbdb")
|
||||
(declare-function bbdb-dwim-mail "bbdb-com")
|
||||
(declare-function bbdb-search "bbdb-com")
|
||||
|
||||
(defgroup company-bbdb nil
|
||||
"Completion backend for BBDB."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-bbdb-modes '(message-mode)
|
||||
"Major modes in which `company-bbdb' may complete."
|
||||
:type '(repeat (symbol :tag "Major mode"))
|
||||
:package-version '(company . "0.8.8"))
|
||||
|
||||
(defun company-bbdb--candidates (arg)
|
||||
(cl-mapcan (lambda (record)
|
||||
(mapcar (lambda (mail) (bbdb-dwim-mail record mail))
|
||||
(bbdb-record-get-field record 'mail)))
|
||||
(eval '(bbdb-search (bbdb-records) arg nil arg))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-bbdb (command &optional arg &rest ignore)
|
||||
"`company-mode' completion backend for BBDB."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-bbdb))
|
||||
(prefix (and (memq major-mode company-bbdb-modes)
|
||||
(featurep 'bbdb-com)
|
||||
(looking-back "^\\(To\\|Cc\\|Bcc\\): *.*? *\\([^,;]*\\)"
|
||||
(line-beginning-position))
|
||||
(match-string-no-properties 2)))
|
||||
(candidates (company-bbdb--candidates arg))
|
||||
(sorted t)
|
||||
(no-cache t)))
|
||||
|
||||
(provide 'company-bbdb)
|
||||
;;; company-bbdb.el ends here
|
Binary file not shown.
|
@ -0,0 +1,189 @@
|
|||
;;; company-capf.el --- company-mode completion-at-point-functions backend -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2013-2018 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; The CAPF back-end provides a bridge to the standard
|
||||
;; completion-at-point-functions facility, and thus can support any major mode
|
||||
;; that defines a proper completion function, including emacs-lisp-mode,
|
||||
;; css-mode and nxml-mode.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defvar company--capf-cache nil)
|
||||
|
||||
(defun company--capf-data ()
|
||||
(let ((cache company--capf-cache))
|
||||
(if (and (equal (current-buffer) (car cache))
|
||||
(equal (point) (car (setq cache (cdr cache))))
|
||||
(equal (buffer-chars-modified-tick) (car (setq cache (cdr cache)))))
|
||||
(cadr cache)
|
||||
(let ((data (company--capf-data-real)))
|
||||
(setq company--capf-cache
|
||||
(list (current-buffer) (point) (buffer-chars-modified-tick) data))
|
||||
data))))
|
||||
|
||||
(defun company--capf-data-real ()
|
||||
(cl-letf* (((default-value 'completion-at-point-functions)
|
||||
;; Ignore tags-completion-at-point-function because it subverts
|
||||
;; company-etags in the default value of company-backends, where
|
||||
;; the latter comes later.
|
||||
(remove 'tags-completion-at-point-function
|
||||
(default-value 'completion-at-point-functions)))
|
||||
(completion-at-point-functions (company--capf-workaround))
|
||||
(data (run-hook-wrapped 'completion-at-point-functions
|
||||
;; Ignore misbehaving functions.
|
||||
#'completion--capf-wrapper 'optimist)))
|
||||
(when (and (consp (cdr data)) (integer-or-marker-p (nth 1 data))) data)))
|
||||
|
||||
(declare-function python-shell-get-process "python")
|
||||
|
||||
(defun company--capf-workaround ()
|
||||
;; For http://debbugs.gnu.org/cgi/bugreport.cgi?bug=18067
|
||||
(if (or (not (listp completion-at-point-functions))
|
||||
(not (memq 'python-completion-complete-at-point completion-at-point-functions))
|
||||
(python-shell-get-process))
|
||||
completion-at-point-functions
|
||||
(remq 'python-completion-complete-at-point completion-at-point-functions)))
|
||||
|
||||
(defun company-capf (command &optional arg &rest _args)
|
||||
"`company-mode' backend using `completion-at-point-functions'."
|
||||
(interactive (list 'interactive))
|
||||
(pcase command
|
||||
(`interactive (company-begin-backend 'company-capf))
|
||||
(`prefix
|
||||
(let ((res (company--capf-data)))
|
||||
(when res
|
||||
(let ((length (plist-get (nthcdr 4 res) :company-prefix-length))
|
||||
(prefix (buffer-substring-no-properties (nth 1 res) (point))))
|
||||
(cond
|
||||
((> (nth 2 res) (point)) 'stop)
|
||||
(length (cons prefix length))
|
||||
(t prefix))))))
|
||||
(`candidates
|
||||
(let ((res (company--capf-data)))
|
||||
(when res
|
||||
(let* ((table (nth 3 res))
|
||||
(pred (plist-get (nthcdr 4 res) :predicate))
|
||||
(meta (completion-metadata
|
||||
(buffer-substring (nth 1 res) (nth 2 res))
|
||||
table pred))
|
||||
(sortfun (cdr (assq 'display-sort-function meta)))
|
||||
(candidates (completion-all-completions arg table pred (length arg)))
|
||||
(last (last candidates))
|
||||
(base-size (and (numberp (cdr last)) (cdr last))))
|
||||
(when base-size
|
||||
(setcdr last nil))
|
||||
(when sortfun
|
||||
(setq candidates (funcall sortfun candidates)))
|
||||
(if (not (zerop (or base-size 0)))
|
||||
(let ((before (substring arg 0 base-size)))
|
||||
(mapcar (lambda (candidate)
|
||||
(concat before candidate))
|
||||
candidates))
|
||||
candidates)))))
|
||||
(`sorted
|
||||
(let ((res (company--capf-data)))
|
||||
(when res
|
||||
(let ((meta (completion-metadata
|
||||
(buffer-substring (nth 1 res) (nth 2 res))
|
||||
(nth 3 res) (plist-get (nthcdr 4 res) :predicate))))
|
||||
(cdr (assq 'display-sort-function meta))))))
|
||||
(`match
|
||||
;; Ask the for the `:company-match' function. If that doesn't help,
|
||||
;; fallback to sniffing for face changes to get a suitable value.
|
||||
(let ((f (plist-get (nthcdr 4 (company--capf-data)) :company-match)))
|
||||
(if f (funcall f arg)
|
||||
(let* ((match-start nil) (pos -1)
|
||||
(prop-value nil) (faces nil)
|
||||
(has-face-p nil) chunks
|
||||
(limit (length arg)))
|
||||
(while (< pos limit)
|
||||
(setq pos
|
||||
(if (< pos 0) 0 (next-property-change pos arg limit)))
|
||||
(setq prop-value (or
|
||||
(get-text-property pos 'face arg)
|
||||
(get-text-property pos 'font-lock-face arg))
|
||||
faces (if (listp prop-value) prop-value (list prop-value))
|
||||
has-face-p (memq 'completions-common-part faces))
|
||||
(cond ((and (not match-start) has-face-p)
|
||||
(setq match-start pos))
|
||||
((and match-start (not has-face-p))
|
||||
(push (cons match-start pos) chunks)
|
||||
(setq match-start nil))))
|
||||
(nreverse chunks)))))
|
||||
(`duplicates t)
|
||||
(`no-cache t) ;Not much can be done here, as long as we handle
|
||||
;non-prefix matches.
|
||||
(`meta
|
||||
(let ((f (plist-get (nthcdr 4 (company--capf-data)) :company-docsig)))
|
||||
(when f (funcall f arg))))
|
||||
(`doc-buffer
|
||||
(let ((f (plist-get (nthcdr 4 (company--capf-data)) :company-doc-buffer)))
|
||||
(when f (funcall f arg))))
|
||||
(`location
|
||||
(let ((f (plist-get (nthcdr 4 (company--capf-data)) :company-location)))
|
||||
(when f (funcall f arg))))
|
||||
(`annotation
|
||||
(save-excursion
|
||||
;; FIXME: `company-begin' sets `company-point' after calling
|
||||
;; `company--begin-new'. We shouldn't rely on `company-point' here,
|
||||
;; better to cache the capf-data value instead. However: we can't just
|
||||
;; save the last capf-data value in `prefix', because that command can
|
||||
;; get called more often than `candidates', and at any point in the
|
||||
;; buffer (https://github.com/company-mode/company-mode/issues/153).
|
||||
;; We could try propertizing the returned prefix string, but it's not
|
||||
;; passed to `annotation', and `company-prefix' is set only after
|
||||
;; `company--strip-duplicates' is called.
|
||||
(when company-point
|
||||
(goto-char company-point))
|
||||
(let ((f (plist-get (nthcdr 4 (company--capf-data)) :annotation-function)))
|
||||
(when f (funcall f arg)))))
|
||||
(`require-match
|
||||
(plist-get (nthcdr 4 (company--capf-data)) :company-require-match))
|
||||
(`init nil) ;Don't bother: plenty of other ways to initialize the code.
|
||||
(`post-completion
|
||||
(company--capf-post-completion arg))
|
||||
))
|
||||
|
||||
(defun company--capf-post-completion (arg)
|
||||
(let* ((res (company--capf-data))
|
||||
(exit-function (plist-get (nthcdr 4 res) :exit-function))
|
||||
(table (nth 3 res))
|
||||
(pred (plist-get (nthcdr 4 res) :predicate)))
|
||||
(if exit-function
|
||||
;; Follow the example of `completion--done'.
|
||||
(funcall exit-function arg
|
||||
;; FIXME: Should probably use an additional heuristic:
|
||||
;; completion-at-point doesn't know when the user picked a
|
||||
;; particular candidate explicitly (it only checks whether
|
||||
;; futher completions exist). Whereas company user can press
|
||||
;; RET (or use implicit completion with company-tng).
|
||||
(if (eq (try-completion arg table pred) t)
|
||||
'finished 'sole)))))
|
||||
|
||||
(provide 'company-capf)
|
||||
|
||||
;;; company-capf.el ends here
|
Binary file not shown.
|
@ -0,0 +1,350 @@
|
|||
;;; company-clang.el --- company-mode completion backend for Clang -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2009, 2011, 2013-2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'company-template)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-clang nil
|
||||
"Completion backend for Clang."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-clang-executable
|
||||
(executable-find "clang")
|
||||
"Location of clang executable."
|
||||
:type 'file)
|
||||
|
||||
(defcustom company-clang-begin-after-member-access t
|
||||
"When non-nil, automatic completion will start whenever the current
|
||||
symbol is preceded by \".\", \"->\" or \"::\", ignoring
|
||||
`company-minimum-prefix-length'.
|
||||
|
||||
If `company-begin-commands' is a list, it should include `c-electric-lt-gt'
|
||||
and `c-electric-colon', for automatic completion right after \">\" and
|
||||
\":\"."
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom company-clang-arguments nil
|
||||
"Additional arguments to pass to clang when completing.
|
||||
Prefix files (-include ...) can be selected with `company-clang-set-prefix'
|
||||
or automatically through a custom `company-clang-prefix-guesser'."
|
||||
:type '(repeat (string :tag "Argument")))
|
||||
|
||||
(defcustom company-clang-prefix-guesser 'company-clang-guess-prefix
|
||||
"A function to determine the prefix file for the current buffer."
|
||||
:type '(function :tag "Guesser function" nil))
|
||||
|
||||
(defvar company-clang-modes '(c-mode c++-mode objc-mode)
|
||||
"Major modes which clang may complete.")
|
||||
|
||||
(defcustom company-clang-insert-arguments t
|
||||
"When non-nil, insert function arguments as a template after completion."
|
||||
:type 'boolean
|
||||
:package-version '(company . "0.8.0"))
|
||||
|
||||
;; prefix ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defvar company-clang--prefix nil)
|
||||
|
||||
(defsubst company-clang--guess-pch-file (file)
|
||||
(let ((dir (directory-file-name (file-name-directory file))))
|
||||
(when (equal (file-name-nondirectory dir) "Classes")
|
||||
(setq dir (file-name-directory dir)))
|
||||
(car (directory-files dir t "\\([^.]h\\|[^h]\\).pch\\'" t))))
|
||||
|
||||
(defsubst company-clang--file-substring (file beg end)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally file nil beg end)
|
||||
(buffer-string)))
|
||||
|
||||
(defun company-clang-guess-prefix ()
|
||||
"Try to guess the prefix file for the current buffer."
|
||||
;; Prefixes seem to be called .pch. Pre-compiled headers do, too.
|
||||
;; So we look at the magic number to rule them out.
|
||||
(let* ((file (company-clang--guess-pch-file buffer-file-name))
|
||||
(magic-number (and file (company-clang--file-substring file 0 4))))
|
||||
(unless (member magic-number '("CPCH" "gpch"))
|
||||
file)))
|
||||
|
||||
(defun company-clang-set-prefix (&optional prefix)
|
||||
"Use PREFIX as a prefix (-include ...) file for clang completion."
|
||||
(interactive (let ((def (funcall company-clang-prefix-guesser)))
|
||||
(unless (stringp def)
|
||||
(setq def default-directory))
|
||||
(list (read-file-name "Prefix file: "
|
||||
(when def (file-name-directory def))
|
||||
def t (when def (file-name-nondirectory def))))))
|
||||
;; TODO: pre-compile?
|
||||
(setq company-clang--prefix (and (stringp prefix)
|
||||
(file-regular-p prefix)
|
||||
prefix)))
|
||||
|
||||
;; Clean-up on exit.
|
||||
(add-hook 'kill-emacs-hook 'company-clang-set-prefix)
|
||||
|
||||
;; parsing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; TODO: Handle Pattern (syntactic hints would be neat).
|
||||
;; Do we ever see OVERLOAD (or OVERRIDE)?
|
||||
(defconst company-clang--completion-pattern
|
||||
"^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?$")
|
||||
|
||||
(defconst company-clang--error-buffer-name "*clang-error*")
|
||||
|
||||
(defun company-clang--lang-option ()
|
||||
(if (eq major-mode 'objc-mode)
|
||||
(if (string= "m" (file-name-extension buffer-file-name))
|
||||
"objective-c" "objective-c++")
|
||||
(substring (symbol-name major-mode) 0 -5)))
|
||||
|
||||
(defun company-clang--parse-output (prefix _objc)
|
||||
(goto-char (point-min))
|
||||
(let ((pattern (format company-clang--completion-pattern
|
||||
(regexp-quote prefix)))
|
||||
(case-fold-search nil)
|
||||
lines match)
|
||||
(while (re-search-forward pattern nil t)
|
||||
(setq match (match-string-no-properties 1))
|
||||
(unless (equal match "Pattern")
|
||||
(save-match-data
|
||||
(when (string-match ":" match)
|
||||
(setq match (substring match 0 (match-beginning 0)))))
|
||||
(let ((meta (match-string-no-properties 2)))
|
||||
(when (and meta (not (string= match meta)))
|
||||
(put-text-property 0 1 'meta
|
||||
(company-clang--strip-formatting meta)
|
||||
match)))
|
||||
(push match lines)))
|
||||
lines))
|
||||
|
||||
(defun company-clang--meta (candidate)
|
||||
(get-text-property 0 'meta candidate))
|
||||
|
||||
(defun company-clang--annotation (candidate)
|
||||
(let ((ann (company-clang--annotation-1 candidate)))
|
||||
(if (not (and ann (string-prefix-p "(*)" ann)))
|
||||
ann
|
||||
(with-temp-buffer
|
||||
(insert ann)
|
||||
(search-backward ")")
|
||||
(let ((pt (1+ (point))))
|
||||
(re-search-forward ".\\_>" nil t)
|
||||
(delete-region pt (point)))
|
||||
(buffer-string)))))
|
||||
|
||||
(defun company-clang--annotation-1 (candidate)
|
||||
(let ((meta (company-clang--meta candidate)))
|
||||
(cond
|
||||
((null meta) nil)
|
||||
((string-match "[^:]:[^:]" meta)
|
||||
(substring meta (1+ (match-beginning 0))))
|
||||
((string-match "(anonymous)" meta) nil)
|
||||
((string-match "\\((.*)[ a-z]*\\'\\)" meta)
|
||||
(let ((paren (match-beginning 1)))
|
||||
(if (not (eq (aref meta (1- paren)) ?>))
|
||||
(match-string 1 meta)
|
||||
(with-temp-buffer
|
||||
(insert meta)
|
||||
(goto-char paren)
|
||||
(substring meta (1- (search-backward "<"))))))))))
|
||||
|
||||
(defun company-clang--strip-formatting (text)
|
||||
(replace-regexp-in-string
|
||||
"#]" " "
|
||||
(replace-regexp-in-string "[<{[]#\\|#[>}]" "" text t)
|
||||
t))
|
||||
|
||||
(defun company-clang--handle-error (res args)
|
||||
(goto-char (point-min))
|
||||
(let* ((buf (get-buffer-create company-clang--error-buffer-name))
|
||||
(cmd (concat company-clang-executable " " (mapconcat 'identity args " ")))
|
||||
(pattern (format company-clang--completion-pattern ""))
|
||||
(message-truncate-lines t)
|
||||
(err (if (re-search-forward pattern nil t)
|
||||
(buffer-substring-no-properties (point-min)
|
||||
(1- (match-beginning 0)))
|
||||
;; Warn the user more aggressively if no match was found.
|
||||
(message "clang failed with error %d: %s" res cmd)
|
||||
(buffer-string))))
|
||||
|
||||
(with-current-buffer buf
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(insert (current-time-string)
|
||||
(format "\nclang failed with error %d:\n" res)
|
||||
cmd "\n\n")
|
||||
(insert err)
|
||||
(setq buffer-read-only t)
|
||||
(goto-char (point-min))))))
|
||||
|
||||
(defun company-clang--start-process (prefix callback &rest args)
|
||||
(let* ((objc (derived-mode-p 'objc-mode))
|
||||
(buf (get-buffer-create "*clang-output*"))
|
||||
;; Looks unnecessary in Emacs 25.1 and later.
|
||||
(process-adaptive-read-buffering nil)
|
||||
(existing-process (get-buffer-process buf)))
|
||||
(when existing-process
|
||||
(kill-process existing-process))
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(setq buffer-undo-list t))
|
||||
(let* ((process-connection-type nil)
|
||||
(process (apply #'start-file-process "company-clang" buf
|
||||
company-clang-executable args)))
|
||||
(set-process-sentinel
|
||||
process
|
||||
(lambda (proc status)
|
||||
(unless (string-match-p "hangup\\|killed" status)
|
||||
(funcall
|
||||
callback
|
||||
(let ((res (process-exit-status proc)))
|
||||
(with-current-buffer buf
|
||||
(unless (eq 0 res)
|
||||
(company-clang--handle-error res args))
|
||||
;; Still try to get any useful input.
|
||||
(company-clang--parse-output prefix objc)))))))
|
||||
(unless (company-clang--auto-save-p)
|
||||
(send-region process (point-min) (point-max))
|
||||
(send-string process "\n")
|
||||
(process-send-eof process)))))
|
||||
|
||||
(defsubst company-clang--build-location (pos)
|
||||
(save-excursion
|
||||
(goto-char pos)
|
||||
(format "%s:%d:%d"
|
||||
(if (company-clang--auto-save-p) buffer-file-name "-")
|
||||
(line-number-at-pos)
|
||||
(1+ (length
|
||||
(encode-coding-region
|
||||
(line-beginning-position)
|
||||
(point)
|
||||
'utf-8
|
||||
t))))))
|
||||
|
||||
(defsubst company-clang--build-complete-args (pos)
|
||||
(append '("-fsyntax-only" "-Xclang" "-code-completion-macros")
|
||||
(unless (company-clang--auto-save-p)
|
||||
(list "-x" (company-clang--lang-option)))
|
||||
company-clang-arguments
|
||||
(when (stringp company-clang--prefix)
|
||||
(list "-include" (expand-file-name company-clang--prefix)))
|
||||
(list "-Xclang" (format "-code-completion-at=%s"
|
||||
(company-clang--build-location pos)))
|
||||
(list (if (company-clang--auto-save-p) buffer-file-name "-"))))
|
||||
|
||||
(defun company-clang--candidates (prefix callback)
|
||||
(and (company-clang--auto-save-p)
|
||||
(buffer-modified-p)
|
||||
(basic-save-buffer))
|
||||
(when (null company-clang--prefix)
|
||||
(company-clang-set-prefix (or (funcall company-clang-prefix-guesser)
|
||||
'none)))
|
||||
(apply 'company-clang--start-process
|
||||
prefix
|
||||
callback
|
||||
(company-clang--build-complete-args
|
||||
(if (company-clang--check-version 4.0 9.0)
|
||||
(point)
|
||||
(- (point) (length prefix))))))
|
||||
|
||||
(defun company-clang--prefix ()
|
||||
(if company-clang-begin-after-member-access
|
||||
(company-grab-symbol-cons "\\.\\|->\\|::" 2)
|
||||
(company-grab-symbol)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defconst company-clang-required-version 1.1)
|
||||
|
||||
(defvar company-clang--version nil)
|
||||
|
||||
(defun company-clang--auto-save-p ()
|
||||
(not
|
||||
(company-clang--check-version 2.9 3.1)))
|
||||
|
||||
(defun company-clang--check-version (min apple-min)
|
||||
(pcase company-clang--version
|
||||
(`(apple . ,ver) (>= ver apple-min))
|
||||
(`(normal . ,ver) (>= ver min))
|
||||
(_ (error "pcase-exhaustive is not in Emacs 24.3!"))))
|
||||
|
||||
(defsubst company-clang-version ()
|
||||
"Return the version of `company-clang-executable'."
|
||||
(with-temp-buffer
|
||||
(call-process company-clang-executable nil t nil "--version")
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward "\\(clang\\|Apple LLVM\\) version \\([0-9.]+\\)" nil t)
|
||||
(cons
|
||||
(if (equal (match-string-no-properties 1) "Apple LLVM")
|
||||
'apple
|
||||
'normal)
|
||||
(string-to-number (match-string-no-properties 2)))
|
||||
0)))
|
||||
|
||||
(defun company-clang (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for Clang.
|
||||
Clang is a parser for C and ObjC. Clang version 1.1 or newer is required.
|
||||
|
||||
Additional command line arguments can be specified in
|
||||
`company-clang-arguments'. Prefix files (-include ...) can be selected
|
||||
with `company-clang-set-prefix' or automatically through a custom
|
||||
`company-clang-prefix-guesser'.
|
||||
|
||||
With Clang versions before 2.9, we have to save the buffer before
|
||||
performing completion. With Clang 2.9 and later, buffer contents are
|
||||
passed via standard input."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-clang))
|
||||
(init (when (memq major-mode company-clang-modes)
|
||||
(unless company-clang-executable
|
||||
(error "Company found no clang executable"))
|
||||
(setq company-clang--version (company-clang-version))
|
||||
(unless (company-clang--check-version
|
||||
company-clang-required-version
|
||||
company-clang-required-version)
|
||||
(error "Company requires clang version %s"
|
||||
company-clang-required-version))))
|
||||
(prefix (and (memq major-mode company-clang-modes)
|
||||
buffer-file-name
|
||||
company-clang-executable
|
||||
(not (company-in-string-or-comment))
|
||||
(or (company-clang--prefix) 'stop)))
|
||||
(candidates (cons :async
|
||||
(lambda (cb) (company-clang--candidates arg cb))))
|
||||
(meta (company-clang--meta arg))
|
||||
(annotation (company-clang--annotation arg))
|
||||
(post-completion (let ((anno (company-clang--annotation arg)))
|
||||
(when (and company-clang-insert-arguments anno)
|
||||
(insert anno)
|
||||
(if (string-match "\\`:[^:]" anno)
|
||||
(company-template-objc-templatify anno)
|
||||
(company-template-c-like-templatify
|
||||
(concat arg anno))))))))
|
||||
|
||||
(provide 'company-clang)
|
||||
;;; company-clang.el ends here
|
Binary file not shown.
|
@ -0,0 +1,206 @@
|
|||
;;; company-cmake.el --- company-mode completion backend for CMake
|
||||
|
||||
;; Copyright (C) 2013-2014, 2017-2018 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Chen Bin <chenbin DOT sh AT gmail>
|
||||
;; Version: 0.2
|
||||
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; company-cmake offers completions for module names, variable names and
|
||||
;; commands used by CMake. And their descriptions.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-cmake nil
|
||||
"Completion backend for CMake."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-cmake-executable
|
||||
(executable-find "cmake")
|
||||
"Location of cmake executable."
|
||||
:type 'file)
|
||||
|
||||
(defvar company-cmake-executable-arguments
|
||||
'("--help-command-list"
|
||||
"--help-module-list"
|
||||
"--help-variable-list")
|
||||
"The arguments we pass to cmake, separately.
|
||||
They affect which types of symbols we get completion candidates for.")
|
||||
|
||||
(defvar company-cmake--completion-pattern
|
||||
"^\\(%s[a-zA-Z0-9_<>]%s\\)$"
|
||||
"Regexp to match the candidates.")
|
||||
|
||||
(defvar company-cmake-modes '(cmake-mode)
|
||||
"Major modes in which cmake may complete.")
|
||||
|
||||
(defvar company-cmake--candidates-cache nil
|
||||
"Cache for the raw candidates.")
|
||||
|
||||
(defvar company-cmake--meta-command-cache nil
|
||||
"Cache for command arguments to retrieve descriptions for the candidates.")
|
||||
|
||||
(defun company-cmake--replace-tags (rlt)
|
||||
(setq rlt (replace-regexp-in-string
|
||||
"\\(.*?\\(IS_GNU\\)?\\)<LANG>\\(.*\\)"
|
||||
(lambda (_match)
|
||||
(mapconcat 'identity
|
||||
(if (match-beginning 2)
|
||||
'("\\1CXX\\3" "\\1C\\3" "\\1G77\\3")
|
||||
'("\\1CXX\\3" "\\1C\\3" "\\1Fortran\\3"))
|
||||
"\n"))
|
||||
rlt t))
|
||||
(setq rlt (replace-regexp-in-string
|
||||
"\\(.*\\)<CONFIG>\\(.*\\)"
|
||||
(mapconcat 'identity '("\\1DEBUG\\2" "\\1RELEASE\\2"
|
||||
"\\1RELWITHDEBINFO\\2" "\\1MINSIZEREL\\2")
|
||||
"\n")
|
||||
rlt))
|
||||
rlt)
|
||||
|
||||
(defun company-cmake--fill-candidates-cache (arg)
|
||||
"Fill candidates cache if needed."
|
||||
(let (rlt)
|
||||
(unless company-cmake--candidates-cache
|
||||
(setq company-cmake--candidates-cache (make-hash-table :test 'equal)))
|
||||
|
||||
;; If hash is empty, fill it.
|
||||
(unless (gethash arg company-cmake--candidates-cache)
|
||||
(with-temp-buffer
|
||||
(let ((res (call-process company-cmake-executable nil t nil arg)))
|
||||
(unless (zerop res)
|
||||
(message "cmake executable exited with error=%d" res)))
|
||||
(setq rlt (buffer-string)))
|
||||
(setq rlt (company-cmake--replace-tags rlt))
|
||||
(puthash arg rlt company-cmake--candidates-cache))
|
||||
))
|
||||
|
||||
(defun company-cmake--parse (prefix content cmd)
|
||||
(let ((start 0)
|
||||
(pattern (format company-cmake--completion-pattern
|
||||
(regexp-quote prefix)
|
||||
(if (zerop (length prefix)) "+" "*")))
|
||||
(lines (split-string content "\n"))
|
||||
match
|
||||
rlt)
|
||||
(dolist (line lines)
|
||||
(when (string-match pattern line)
|
||||
(let ((match (match-string 1 line)))
|
||||
(when match
|
||||
(puthash match cmd company-cmake--meta-command-cache)
|
||||
(push match rlt)))))
|
||||
rlt))
|
||||
|
||||
(defun company-cmake--candidates (prefix)
|
||||
(let (results
|
||||
cmd-opts
|
||||
str)
|
||||
|
||||
(unless company-cmake--meta-command-cache
|
||||
(setq company-cmake--meta-command-cache (make-hash-table :test 'equal)))
|
||||
|
||||
(dolist (arg company-cmake-executable-arguments)
|
||||
(company-cmake--fill-candidates-cache arg)
|
||||
(setq cmd-opts (replace-regexp-in-string "-list$" "" arg) )
|
||||
|
||||
(setq str (gethash arg company-cmake--candidates-cache))
|
||||
(when str
|
||||
(setq results (nconc results
|
||||
(company-cmake--parse prefix str cmd-opts)))))
|
||||
results))
|
||||
|
||||
(defun company-cmake--unexpand-candidate (candidate)
|
||||
(cond
|
||||
((string-match "^CMAKE_\\(C\\|CXX\\|Fortran\\)\\(_.*\\)$" candidate)
|
||||
(setq candidate (concat "CMAKE_<LANG>" (match-string 2 candidate))))
|
||||
|
||||
;; C flags
|
||||
((string-match "^\\(.*_\\)IS_GNU\\(C\\|CXX\\|G77\\)$" candidate)
|
||||
(setq candidate (concat (match-string 1 candidate) "IS_GNU<LANG>")))
|
||||
|
||||
;; C flags
|
||||
((string-match "^\\(.*_\\)OVERRIDE_\\(C\\|CXX\\|Fortran\\)$" candidate)
|
||||
(setq candidate (concat (match-string 1 candidate) "OVERRIDE_<LANG>")))
|
||||
|
||||
((string-match "^\\(.*\\)\\(_DEBUG\\|_RELEASE\\|_RELWITHDEBINFO\\|_MINSIZEREL\\)\\(.*\\)$" candidate)
|
||||
(setq candidate (concat (match-string 1 candidate)
|
||||
"_<CONFIG>"
|
||||
(match-string 3 candidate)))))
|
||||
candidate)
|
||||
|
||||
(defun company-cmake--meta (candidate)
|
||||
(let ((cmd-opts (gethash candidate company-cmake--meta-command-cache))
|
||||
result)
|
||||
(setq candidate (company-cmake--unexpand-candidate candidate))
|
||||
|
||||
;; Don't cache the documentation of every candidate (command)
|
||||
;; Cache in this case will cost too much memory.
|
||||
(with-temp-buffer
|
||||
(call-process company-cmake-executable nil t nil cmd-opts candidate)
|
||||
;; Go to the third line, trim it and return the result.
|
||||
;; Tested with cmake 2.8.9.
|
||||
(goto-char (point-min))
|
||||
(forward-line 2)
|
||||
(setq result (buffer-substring-no-properties (line-beginning-position)
|
||||
(line-end-position)))
|
||||
(setq result (replace-regexp-in-string "^[ \t\n\r]+" "" result))
|
||||
result)))
|
||||
|
||||
(defun company-cmake--doc-buffer (candidate)
|
||||
(let ((cmd-opts (gethash candidate company-cmake--meta-command-cache)))
|
||||
|
||||
(setq candidate (company-cmake--unexpand-candidate candidate))
|
||||
(with-temp-buffer
|
||||
(call-process company-cmake-executable nil t nil cmd-opts candidate)
|
||||
;; Go to the third line, trim it and return the doc buffer.
|
||||
;; Tested with cmake 2.8.9.
|
||||
(goto-char (point-min))
|
||||
(forward-line 2)
|
||||
(company-doc-buffer
|
||||
(buffer-substring-no-properties (line-beginning-position)
|
||||
(point-max))))))
|
||||
|
||||
(defun company-cmake-prefix-dollar-brace-p ()
|
||||
"Test if the current symbol follows ${."
|
||||
(save-excursion
|
||||
(skip-syntax-backward "w_")
|
||||
(and (eq (char-before (point)) ?\{)
|
||||
(eq (char-before (1- (point))) ?$))))
|
||||
|
||||
(defun company-cmake (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for CMake.
|
||||
CMake is a cross-platform, open-source make system."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-cmake))
|
||||
(init (when (memq major-mode company-cmake-modes)
|
||||
(unless company-cmake-executable
|
||||
(error "Company found no cmake executable"))))
|
||||
(prefix (and (memq major-mode company-cmake-modes)
|
||||
(or (not (company-in-string-or-comment))
|
||||
(company-cmake-prefix-dollar-brace-p))
|
||||
(company-grab-symbol)))
|
||||
(candidates (company-cmake--candidates arg))
|
||||
(meta (company-cmake--meta arg))
|
||||
(doc-buffer (company-cmake--doc-buffer arg))
|
||||
))
|
||||
|
||||
(provide 'company-cmake)
|
||||
;;; company-cmake.el ends here
|
Binary file not shown.
|
@ -0,0 +1,446 @@
|
|||
;;; company-css.el --- company-mode completion backend for css-mode -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2009, 2011, 2014, 2018 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; In Emacs >= 26, company-capf is used instead.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(declare-function web-mode-language-at-pos "web-mode" (&optional pos))
|
||||
|
||||
(defconst company-css-property-alist
|
||||
;; see http://www.w3.org/TR/CSS21/propidx.html
|
||||
'(("azimuth" angle "left-side" "far-left" "left" "center-left" "center"
|
||||
"center-right" "right" "far-right" "right-side" "behind" "leftwards"
|
||||
"rightwards")
|
||||
("background" background-color background-image background-repeat
|
||||
background-attachment background-position
|
||||
background-clip background-origin background-size)
|
||||
("background-attachment" "scroll" "fixed")
|
||||
("background-color" color "transparent")
|
||||
("background-image" uri "none")
|
||||
("background-position" percentage length "left" "center" "right" percentage
|
||||
length "top" "center" "bottom" "left" "center" "right" "top" "center"
|
||||
"bottom")
|
||||
("background-repeat" "repeat" "repeat-x" "repeat-y" "no-repeat")
|
||||
("border" border-width border-style border-color)
|
||||
("border-bottom" border)
|
||||
("border-bottom-color" border-color)
|
||||
("border-bottom-style" border-style)
|
||||
("border-bottom-width" border-width)
|
||||
("border-collapse" "collapse" "separate")
|
||||
("border-color" color "transparent")
|
||||
("border-left" border)
|
||||
("border-left-color" border-color)
|
||||
("border-left-style" border-style)
|
||||
("border-left-width" border-width)
|
||||
("border-right" border)
|
||||
("border-right-color" border-color)
|
||||
("border-right-style" border-style)
|
||||
("border-right-width" border-width)
|
||||
("border-spacing" length length)
|
||||
("border-style" border-style)
|
||||
("border-top" border)
|
||||
("border-top-color" border-color)
|
||||
("border-top-style" border-style)
|
||||
("border-top-width" border-width)
|
||||
("border-width" border-width)
|
||||
("bottom" length percentage "auto")
|
||||
("caption-side" "top" "bottom")
|
||||
("clear" "none" "left" "right" "both")
|
||||
("clip" shape "auto")
|
||||
("color" color)
|
||||
("content" "normal" "none" string uri counter "attr()" "open-quote"
|
||||
"close-quote" "no-open-quote" "no-close-quote")
|
||||
("counter-increment" identifier integer "none")
|
||||
("counter-reset" identifier integer "none")
|
||||
("cue" cue-before cue-after)
|
||||
("cue-after" uri "none")
|
||||
("cue-before" uri "none")
|
||||
("cursor" uri "*" "auto" "crosshair" "default" "pointer" "move" "e-resize"
|
||||
"ne-resize" "nw-resize" "n-resize" "se-resize" "sw-resize" "s-resize"
|
||||
"w-resize" "text" "wait" "help" "progress")
|
||||
("direction" "ltr" "rtl")
|
||||
("display" "inline" "block" "list-item" "run-in" "inline-block" "table"
|
||||
"inline-table" "table-row-group" "table-header-group" "table-footer-group"
|
||||
"table-row" "table-column-group" "table-column" "table-cell"
|
||||
"table-caption" "none")
|
||||
("elevation" angle "below" "level" "above" "higher" "lower")
|
||||
("empty-cells" "show" "hide")
|
||||
("float" "left" "right" "none")
|
||||
("font" font-style font-weight font-size "/" line-height
|
||||
font-family "caption" "icon" "menu" "message-box" "small-caption"
|
||||
"status-bar" "normal" "small-caps"
|
||||
;; CSS3
|
||||
font-stretch)
|
||||
("font-family" family-name generic-family)
|
||||
("font-size" absolute-size relative-size length percentage)
|
||||
("font-style" "normal" "italic" "oblique")
|
||||
("font-weight" "normal" "bold" "bolder" "lighter" "100" "200" "300" "400"
|
||||
"500" "600" "700" "800" "900")
|
||||
("height" length percentage "auto")
|
||||
("left" length percentage "auto")
|
||||
("letter-spacing" "normal" length)
|
||||
("line-height" "normal" number length percentage)
|
||||
("list-style" list-style-type list-style-position list-style-image)
|
||||
("list-style-image" uri "none")
|
||||
("list-style-position" "inside" "outside")
|
||||
("list-style-type" "disc" "circle" "square" "decimal" "decimal-leading-zero"
|
||||
"lower-roman" "upper-roman" "lower-greek" "lower-latin" "upper-latin"
|
||||
"armenian" "georgian" "lower-alpha" "upper-alpha" "none")
|
||||
("margin" margin-width)
|
||||
("margin-bottom" margin-width)
|
||||
("margin-left" margin-width)
|
||||
("margin-right" margin-width)
|
||||
("margin-top" margin-width)
|
||||
("max-height" length percentage "none")
|
||||
("max-width" length percentage "none")
|
||||
("min-height" length percentage)
|
||||
("min-width" length percentage)
|
||||
("orphans" integer)
|
||||
("outline" outline-color outline-style outline-width)
|
||||
("outline-color" color "invert")
|
||||
("outline-style" border-style)
|
||||
("outline-width" border-width)
|
||||
("overflow" "visible" "hidden" "scroll" "auto"
|
||||
;; CSS3:
|
||||
"no-display" "no-content")
|
||||
("padding" padding-width)
|
||||
("padding-bottom" padding-width)
|
||||
("padding-left" padding-width)
|
||||
("padding-right" padding-width)
|
||||
("padding-top" padding-width)
|
||||
("page-break-after" "auto" "always" "avoid" "left" "right")
|
||||
("page-break-before" "auto" "always" "avoid" "left" "right")
|
||||
("page-break-inside" "avoid" "auto")
|
||||
("pause" time percentage)
|
||||
("pause-after" time percentage)
|
||||
("pause-before" time percentage)
|
||||
("pitch" frequency "x-low" "low" "medium" "high" "x-high")
|
||||
("pitch-range" number)
|
||||
("play-during" uri "mix" "repeat" "auto" "none")
|
||||
("position" "static" "relative" "absolute" "fixed")
|
||||
("quotes" string string "none")
|
||||
("richness" number)
|
||||
("right" length percentage "auto")
|
||||
("speak" "normal" "none" "spell-out")
|
||||
("speak-header" "once" "always")
|
||||
("speak-numeral" "digits" "continuous")
|
||||
("speak-punctuation" "code" "none")
|
||||
("speech-rate" number "x-slow" "slow" "medium" "fast" "x-fast" "faster"
|
||||
"slower")
|
||||
("stress" number)
|
||||
("table-layout" "auto" "fixed")
|
||||
("text-align" "left" "right" "center" "justify")
|
||||
("text-indent" length percentage)
|
||||
("text-transform" "capitalize" "uppercase" "lowercase" "none")
|
||||
("top" length percentage "auto")
|
||||
("unicode-bidi" "normal" "embed" "bidi-override")
|
||||
("vertical-align" "baseline" "sub" "super" "top" "text-top" "middle"
|
||||
"bottom" "text-bottom" percentage length)
|
||||
("visibility" "visible" "hidden" "collapse")
|
||||
("voice-family" specific-voice generic-voice "*" specific-voice
|
||||
generic-voice)
|
||||
("volume" number percentage "silent" "x-soft" "soft" "medium" "loud"
|
||||
"x-loud")
|
||||
("white-space" "normal" "pre" "nowrap" "pre-wrap" "pre-line")
|
||||
("widows" integer)
|
||||
("width" length percentage "auto")
|
||||
("word-spacing" "normal" length)
|
||||
("z-index" "auto" integer)
|
||||
;; CSS3
|
||||
("align-content" align-stretch "space-between" "space-around")
|
||||
("align-items" align-stretch "baseline")
|
||||
("align-self" align-items "auto")
|
||||
("animation" animation-name animation-duration animation-timing-function
|
||||
animation-delay animation-iteration-count animation-direction
|
||||
animation-fill-mode)
|
||||
("animation-delay" time)
|
||||
("animation-direction" "normal" "reverse" "alternate" "alternate-reverse")
|
||||
("animation-duration" time)
|
||||
("animation-fill-mode" "none" "forwards" "backwards" "both")
|
||||
("animation-iteration-count" integer "infinite")
|
||||
("animation-name" "none")
|
||||
("animation-play-state" "paused" "running")
|
||||
("animation-timing-function" transition-timing-function
|
||||
"step-start" "step-end" "steps(,)")
|
||||
("backface-visibility" "visible" "hidden")
|
||||
("background-clip" background-origin)
|
||||
("background-origin" "border-box" "padding-box" "content-box")
|
||||
("background-size" length percentage "auto" "cover" "contain")
|
||||
("border-image" border-image-outset border-image-repeat border-image-source
|
||||
border-image-slice border-image-width)
|
||||
("border-image-outset" length)
|
||||
("border-image-repeat" "stretch" "repeat" "round" "space")
|
||||
("border-image-source" uri "none")
|
||||
("border-image-slice" length)
|
||||
("border-image-width" length percentage)
|
||||
("border-radius" length)
|
||||
("border-top-left-radius" length)
|
||||
("border-top-right-radius" length)
|
||||
("border-bottom-left-radius" length)
|
||||
("border-bottom-right-radius" length)
|
||||
("box-decoration-break" "slice" "clone")
|
||||
("box-shadow" length color)
|
||||
("box-sizing" "content-box" "border-box")
|
||||
("break-after" "auto" "always" "avoid" "left" "right" "page" "column"
|
||||
"avoid-page" "avoid-column")
|
||||
("break-before" break-after)
|
||||
("break-inside" "avoid" "auto")
|
||||
("columns" column-width column-count)
|
||||
("column-count" integer)
|
||||
("column-fill" "auto" "balance")
|
||||
("column-gap" length "normal")
|
||||
("column-rule" column-rule-width column-rule-style column-rule-color)
|
||||
("column-rule-color" color)
|
||||
("column-rule-style" border-style)
|
||||
("column-rule-width" border-width)
|
||||
("column-span" "all" "none")
|
||||
("column-width" length "auto")
|
||||
("filter" url "blur()" "brightness()" "contrast()" "drop-shadow()"
|
||||
"grayscale()" "hue-rotate()" "invert()" "opacity()" "saturate()" "sepia()")
|
||||
("flex" flex-grow flex-shrink flex-basis)
|
||||
("flex-basis" percentage length "auto")
|
||||
("flex-direction" "row" "row-reverse" "column" "column-reverse")
|
||||
("flex-flow" flex-direction flex-wrap)
|
||||
("flex-grow" number)
|
||||
("flex-shrink" number)
|
||||
("flex-wrap" "nowrap" "wrap" "wrap-reverse")
|
||||
("font-feature-setting" normal string number)
|
||||
("font-kerning" "auto" "normal" "none")
|
||||
("font-language-override" "normal" string)
|
||||
("font-size-adjust" "none" number)
|
||||
("font-stretch" "normal" "ultra-condensed" "extra-condensed" "condensed"
|
||||
"semi-condensed" "semi-expanded" "expanded" "extra-expanded" "ultra-expanded")
|
||||
("font-synthesis" "none" "weight" "style")
|
||||
("font-variant" font-variant-alternates font-variant-caps
|
||||
font-variant-east-asian font-variant-ligatures font-variant-numeric
|
||||
font-variant-position)
|
||||
("font-variant-alternates" "normal" "historical-forms" "stylistic()"
|
||||
"styleset()" "character-variant()" "swash()" "ornaments()" "annotation()")
|
||||
("font-variant-caps" "normal" "small-caps" "all-small-caps" "petite-caps"
|
||||
"all-petite-caps" "unicase" "titling-caps")
|
||||
("font-variant-east-asian" "jis78" "jis83" "jis90" "jis04" "simplified"
|
||||
"traditional" "full-width" "proportional-width" "ruby")
|
||||
("font-variant-ligatures" "normal" "none" "common-ligatures"
|
||||
"no-common-ligatures" "discretionary-ligatures" "no-discretionary-ligatures"
|
||||
"historical-ligatures" "no-historical-ligatures" "contextual" "no-contextual")
|
||||
("font-variant-numeric" "normal" "ordinal" "slashed-zero"
|
||||
"lining-nums" "oldstyle-nums" "proportional-nums" "tabular-nums"
|
||||
"diagonal-fractions" "stacked-fractions")
|
||||
("font-variant-position" "normal" "sub" "super")
|
||||
("hyphens" "none" "manual" "auto")
|
||||
("justify-content" align-common "space-between" "space-around")
|
||||
("line-break" "auto" "loose" "normal" "strict")
|
||||
("marquee-direction" "forward" "reverse")
|
||||
("marquee-play-count" integer "infinite")
|
||||
("marquee-speed" "slow" "normal" "fast")
|
||||
("marquee-style" "scroll" "slide" "alternate")
|
||||
("opacity" number)
|
||||
("order" number)
|
||||
("outline-offset" length)
|
||||
("overflow-x" overflow)
|
||||
("overflow-y" overflow)
|
||||
("overflow-style" "auto" "marquee-line" "marquee-block")
|
||||
("overflow-wrap" "normal" "break-word")
|
||||
("perspective" "none" length)
|
||||
("perspective-origin" percentage length "left" "center" "right" "top" "bottom")
|
||||
("resize" "none" "both" "horizontal" "vertical")
|
||||
("tab-size" integer length)
|
||||
("text-align-last" "auto" "start" "end" "left" "right" "center" "justify")
|
||||
("text-decoration" text-decoration-color text-decoration-line text-decoration-style)
|
||||
("text-decoration-color" color)
|
||||
("text-decoration-line" "none" "underline" "overline" "line-through" "blink")
|
||||
("text-decoration-style" "solid" "double" "dotted" "dashed" "wavy")
|
||||
("text-overflow" "clip" "ellipsis")
|
||||
("text-shadow" color length)
|
||||
("text-underline-position" "auto" "under" "left" "right")
|
||||
("transform" "matrix(,,,,,)" "translate(,)" "translateX()" "translateY()"
|
||||
"scale()" "scaleX()" "scaleY()" "rotate()" "skewX()" "skewY()" "none")
|
||||
("transform-origin" perspective-origin)
|
||||
("transform-style" "flat" "preserve-3d")
|
||||
("transition" transition-property transition-duration
|
||||
transition-timing-function transition-delay)
|
||||
("transition-delay" time)
|
||||
("transition-duration" time)
|
||||
("transition-timing-function"
|
||||
"ease" "linear" "ease-in" "ease-out" "ease-in-out" "cubic-bezier(,,,)")
|
||||
("transition-property" "none" "all" identifier)
|
||||
("word-wrap" overflow-wrap)
|
||||
("word-break" "normal" "break-all" "keep-all"))
|
||||
"A list of CSS properties and their possible values.")
|
||||
|
||||
(defconst company-css-value-classes
|
||||
'((absolute-size "xx-small" "x-small" "small" "medium" "large" "x-large"
|
||||
"xx-large")
|
||||
(align-common "flex-start" "flex-end" "center")
|
||||
(align-stretch align-common "stretch")
|
||||
(border-style "none" "hidden" "dotted" "dashed" "solid" "double" "groove"
|
||||
"ridge" "inset" "outset")
|
||||
(border-width "thick" "medium" "thin")
|
||||
(color "aqua" "black" "blue" "fuchsia" "gray" "green" "lime" "maroon" "navy"
|
||||
"olive" "orange" "purple" "red" "silver" "teal" "white" "yellow")
|
||||
(counter "counter(,)")
|
||||
(family-name "Courier" "Helvetica" "Times")
|
||||
(generic-family "serif" "sans-serif" "cursive" "fantasy" "monospace")
|
||||
(generic-voice "male" "female" "child")
|
||||
(margin-width "auto") ;; length percentage
|
||||
(relative-size "larger" "smaller")
|
||||
(shape "rect(,,,)")
|
||||
(uri "url()"))
|
||||
"A list of CSS property value classes and their contents.")
|
||||
;; missing, because not completable
|
||||
;; <angle><frequency><identifier><integer><length><number><padding-width>
|
||||
;; <percentage><specific-voice><string><time><uri>
|
||||
|
||||
(defconst company-css-html-tags
|
||||
'("a" "abbr" "acronym" "address" "applet" "area" "b" "base" "basefont" "bdo"
|
||||
"big" "blockquote" "body" "br" "button" "caption" "center" "cite" "code"
|
||||
"col" "colgroup" "dd" "del" "dfn" "dir" "div" "dl" "dt" "em" "fieldset"
|
||||
"font" "form" "frame" "frameset" "h1" "h2" "h3" "h4" "h5" "h6" "head" "hr"
|
||||
"html" "i" "iframe" "img" "input" "ins" "isindex" "kbd" "label" "legend"
|
||||
"li" "link" "map" "menu" "meta" "noframes" "noscript" "object" "ol"
|
||||
"optgroup" "option" "p" "param" "pre" "q" "s" "samp" "script" "select"
|
||||
"small" "span" "strike" "strong" "style" "sub" "sup" "table" "tbody" "td"
|
||||
"textarea" "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var"
|
||||
;; HTML5
|
||||
"section" "article" "aside" "header" "footer" "nav" "figure" "figcaption"
|
||||
"time" "mark" "main")
|
||||
"A list of HTML tags for use in CSS completion.")
|
||||
|
||||
(defconst company-css-pseudo-classes
|
||||
'("active" "after" "before" "first" "first-child" "first-letter" "first-line"
|
||||
"focus" "hover" "lang" "left" "link" "right" "visited")
|
||||
"Identifiers for CSS pseudo-elements and pseudo-classes.")
|
||||
|
||||
(defconst company-css-property-cache (make-hash-table :size 115 :test 'equal))
|
||||
|
||||
(defun company-css-property-values (attribute)
|
||||
"Access the `company-css-property-alist' cached and flattened."
|
||||
(or (gethash attribute company-css-property-cache)
|
||||
(let (results)
|
||||
(dolist (value (cdr (assoc attribute company-css-property-alist)))
|
||||
(if (symbolp value)
|
||||
(dolist (child (or (cdr (assoc value company-css-value-classes))
|
||||
(company-css-property-values
|
||||
(symbol-name value))))
|
||||
(push child results))
|
||||
(push value results)))
|
||||
(setq results (sort results 'string<))
|
||||
(puthash attribute
|
||||
(if (fboundp 'delete-consecutive-dups)
|
||||
(delete-consecutive-dups results)
|
||||
(delete-dups results))
|
||||
company-css-property-cache)
|
||||
results)))
|
||||
|
||||
;;; bracket detection
|
||||
|
||||
(defconst company-css-braces-syntax-table
|
||||
(let ((table (make-syntax-table)))
|
||||
(setf (aref table ?{) '(4 . 125))
|
||||
(setf (aref table ?}) '(5 . 123))
|
||||
table)
|
||||
"A syntax table giving { and } paren syntax.")
|
||||
|
||||
(defun company-css-inside-braces-p ()
|
||||
"Return non-nil, if point is within matched { and }."
|
||||
(ignore-errors
|
||||
(with-syntax-table company-css-braces-syntax-table
|
||||
(let ((parse-sexp-ignore-comments t))
|
||||
(scan-lists (point) -1 1)))))
|
||||
|
||||
;;; tags
|
||||
(defconst company-css-tag-regexp
|
||||
(concat "\\(?:\\`\\|}\\)[[:space:]]*"
|
||||
;; multiple
|
||||
"\\(?:"
|
||||
;; previous tags:
|
||||
"\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
|
||||
;; space or selectors
|
||||
"\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
|
||||
"\\)*"
|
||||
"\\(\\(?:#\\|\\_<[[:alpha:]]\\)\\(?:[[:alnum:]-#]*\\_>\\)?\\_>\\|\\)"
|
||||
"\\=")
|
||||
"A regular expression matching CSS tags.")
|
||||
|
||||
;;; pseudo id
|
||||
(defconst company-css-pseudo-regexp
|
||||
(concat "\\(?:\\`\\|}\\)[[:space:]]*"
|
||||
;; multiple
|
||||
"\\(?:"
|
||||
;; previous tags:
|
||||
"\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
|
||||
;; space or delimiters
|
||||
"\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
|
||||
"\\)*"
|
||||
"\\(?:\\(?:\\#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\):"
|
||||
"\\([[:alpha:]-]+\\_>\\|\\)\\_>\\=")
|
||||
"A regular expression matching CSS pseudo classes.")
|
||||
|
||||
;;; properties
|
||||
|
||||
(defun company-css-grab-property ()
|
||||
"Return the CSS property before point, if any.
|
||||
Returns \"\" if no property found, but feasible at this position."
|
||||
(when (company-css-inside-braces-p)
|
||||
(company-grab-symbol)))
|
||||
|
||||
;;; values
|
||||
(defconst company-css-property-value-regexp
|
||||
"\\_<\\([[:alpha:]-]+\\):\\(?:[^{};]*[[:space:]]+\\)?\\([^{};]*\\_>\\|\\)\\="
|
||||
"A regular expression matching CSS tags.")
|
||||
|
||||
;;;###autoload
|
||||
(defun company-css (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for `css-mode'."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-css))
|
||||
(prefix (and (or (derived-mode-p 'css-mode)
|
||||
(and (derived-mode-p 'web-mode)
|
||||
(string= (web-mode-language-at-pos) "css")))
|
||||
(or (company-grab company-css-tag-regexp 1)
|
||||
(company-grab company-css-pseudo-regexp 1)
|
||||
(company-grab company-css-property-value-regexp 2
|
||||
(line-beginning-position))
|
||||
(company-css-grab-property))))
|
||||
(candidates
|
||||
(cond
|
||||
((company-grab company-css-tag-regexp 1)
|
||||
(all-completions arg company-css-html-tags))
|
||||
((company-grab company-css-pseudo-regexp 1)
|
||||
(all-completions arg company-css-pseudo-classes))
|
||||
((company-grab company-css-property-value-regexp 2
|
||||
(line-beginning-position))
|
||||
(all-completions arg
|
||||
(company-css-property-values
|
||||
(company-grab company-css-property-value-regexp 1))))
|
||||
((company-css-grab-property)
|
||||
(all-completions arg company-css-property-alist))))
|
||||
(sorted t)))
|
||||
|
||||
(provide 'company-css)
|
||||
;;; company-css.el ends here
|
Binary file not shown.
|
@ -0,0 +1,104 @@
|
|||
;;; company-dabbrev-code.el --- dabbrev-like company-mode backend for code -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2009, 2011, 2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'company-dabbrev)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-dabbrev-code nil
|
||||
"dabbrev-like completion backend for code."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-dabbrev-code-modes
|
||||
'(prog-mode
|
||||
batch-file-mode csharp-mode css-mode erlang-mode haskell-mode jde-mode
|
||||
lua-mode python-mode)
|
||||
"Modes that use `company-dabbrev-code'.
|
||||
In all these modes (and their derivatives) `company-dabbrev-code' will
|
||||
complete only symbols, not text in comments or strings. In other modes
|
||||
`company-dabbrev-code' will pass control to other backends
|
||||
\(e.g. `company-dabbrev'\). Value t means complete in all modes."
|
||||
:type '(choice (repeat :tag "Some modes" (symbol :tag "Major mode"))
|
||||
(const :tag "All modes" t)))
|
||||
|
||||
(defcustom company-dabbrev-code-other-buffers t
|
||||
"Determines whether `company-dabbrev-code' should search other buffers.
|
||||
If `all', search all other buffers, except the ignored ones. If t, search
|
||||
buffers with the same major mode. If `code', search all buffers with major
|
||||
modes in `company-dabbrev-code-modes', or derived from one of them. See
|
||||
also `company-dabbrev-code-time-limit'."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(const :tag "Same major mode" t)
|
||||
(const :tag "Code major modes" code)
|
||||
(const :tag "All" all)))
|
||||
|
||||
(defcustom company-dabbrev-code-time-limit .1
|
||||
"Determines how long `company-dabbrev-code' should look for matches."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(number :tag "Seconds")))
|
||||
|
||||
(defcustom company-dabbrev-code-everywhere nil
|
||||
"Non-nil to offer completions in comments and strings."
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom company-dabbrev-code-ignore-case nil
|
||||
"Non-nil to ignore case when collecting completion candidates."
|
||||
:type 'boolean)
|
||||
|
||||
(defun company-dabbrev-code--make-regexp (prefix)
|
||||
(concat "\\_<" (if (equal prefix "")
|
||||
"\\([a-zA-Z]\\|\\s_\\)"
|
||||
(regexp-quote prefix))
|
||||
"\\(\\sw\\|\\s_\\)*\\_>"))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-dabbrev-code (command &optional arg &rest ignored)
|
||||
"dabbrev-like `company-mode' backend for code.
|
||||
The backend looks for all symbols in the current buffer that aren't in
|
||||
comments or strings."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-dabbrev-code))
|
||||
(prefix (and (or (eq t company-dabbrev-code-modes)
|
||||
(apply #'derived-mode-p company-dabbrev-code-modes))
|
||||
(or company-dabbrev-code-everywhere
|
||||
(not (company-in-string-or-comment)))
|
||||
(or (company-grab-symbol) 'stop)))
|
||||
(candidates (let ((case-fold-search company-dabbrev-code-ignore-case))
|
||||
(company-dabbrev--search
|
||||
(company-dabbrev-code--make-regexp arg)
|
||||
company-dabbrev-code-time-limit
|
||||
(pcase company-dabbrev-code-other-buffers
|
||||
(`t (list major-mode))
|
||||
(`code company-dabbrev-code-modes)
|
||||
(`all `all))
|
||||
(not company-dabbrev-code-everywhere))))
|
||||
(ignore-case company-dabbrev-code-ignore-case)
|
||||
(duplicates t)))
|
||||
|
||||
(provide 'company-dabbrev-code)
|
||||
;;; company-dabbrev-code.el ends here
|
Binary file not shown.
|
@ -0,0 +1,206 @@
|
|||
;;; company-dabbrev.el --- dabbrev-like company-mode completion backend -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2009, 2011, 2014, 2015, 2016 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-dabbrev nil
|
||||
"dabbrev-like completion backend."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-dabbrev-other-buffers 'all
|
||||
"Determines whether `company-dabbrev' should search other buffers.
|
||||
If `all', search all other buffers, except the ignored ones. If t, search
|
||||
buffers with the same major mode. See also `company-dabbrev-time-limit'."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(const :tag "Same major mode" t)
|
||||
(const :tag "All" all)))
|
||||
|
||||
(defcustom company-dabbrev-ignore-buffers "\\`[ *]"
|
||||
"Regexp matching the names of buffers to ignore.
|
||||
Or a function that returns non-nil for such buffers."
|
||||
:type '(choice (regexp :tag "Regexp")
|
||||
(function :tag "Predicate"))
|
||||
:package-version '(company . "0.9.0"))
|
||||
|
||||
(defcustom company-dabbrev-time-limit .1
|
||||
"Determines how many seconds `company-dabbrev' should look for matches."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(number :tag "Seconds")))
|
||||
|
||||
(defcustom company-dabbrev-char-regexp "\\sw"
|
||||
"A regular expression matching the characters `company-dabbrev' looks for."
|
||||
:type 'regexp)
|
||||
|
||||
(defcustom company-dabbrev-ignore-case 'keep-prefix
|
||||
"Non-nil to ignore case when collecting completion candidates.
|
||||
When it's `keep-prefix', the text before point will remain unchanged after
|
||||
candidate is inserted, even some of its characters have different case."
|
||||
:type '(choice
|
||||
(const :tag "Don't ignore case" nil)
|
||||
(const :tag "Ignore case" t)
|
||||
(const :tag "Keep case before point" keep-prefix)))
|
||||
|
||||
(defcustom company-dabbrev-downcase 'case-replace
|
||||
"Whether to downcase the returned candidates.
|
||||
|
||||
The value of nil means keep them as-is.
|
||||
`case-replace' means use the value of `case-replace'.
|
||||
Any other value means downcase.
|
||||
|
||||
If you set this value to nil, you may also want to set
|
||||
`company-dabbrev-ignore-case' to any value other than `keep-prefix'."
|
||||
:type '(choice
|
||||
(const :tag "Keep as-is" nil)
|
||||
(const :tag "Downcase" t)
|
||||
(const :tag "Use case-replace" case-replace)))
|
||||
|
||||
(defcustom company-dabbrev-minimum-length 4
|
||||
"The minimum length for the completion candidate to be included.
|
||||
This variable affects both `company-dabbrev' and `company-dabbrev-code'."
|
||||
:type 'integer
|
||||
:package-version '(company . "0.8.3"))
|
||||
|
||||
(defcustom company-dabbrev-ignore-invisible nil
|
||||
"Non-nil to skip invisible text."
|
||||
:type 'boolean
|
||||
:package-version '(company . "0.9.0"))
|
||||
|
||||
(defmacro company-dabbrev--time-limit-while (test start limit freq &rest body)
|
||||
(declare (indent 3) (debug t))
|
||||
`(let ((company-time-limit-while-counter 0))
|
||||
(catch 'done
|
||||
(while ,test
|
||||
,@body
|
||||
(and ,limit
|
||||
(= (cl-incf company-time-limit-while-counter) ,freq)
|
||||
(setq company-time-limit-while-counter 0)
|
||||
(> (float-time (time-since ,start)) ,limit)
|
||||
(throw 'done 'company-time-out))))))
|
||||
|
||||
(defun company-dabbrev--make-regexp ()
|
||||
(concat "\\(?:" company-dabbrev-char-regexp "\\)+"))
|
||||
|
||||
(defun company-dabbrev--search-buffer (regexp pos symbols start limit
|
||||
ignore-comments)
|
||||
(save-excursion
|
||||
(cl-labels ((maybe-collect-match
|
||||
()
|
||||
(let ((match (match-string-no-properties 0)))
|
||||
(when (and (>= (length match) company-dabbrev-minimum-length)
|
||||
(not (and company-dabbrev-ignore-invisible
|
||||
(invisible-p (match-beginning 0)))))
|
||||
(push match symbols)))))
|
||||
(goto-char (if pos (1- pos) (point-min)))
|
||||
;; Search before pos.
|
||||
(let ((tmp-end (point)))
|
||||
(company-dabbrev--time-limit-while (and (not (input-pending-p))
|
||||
(> tmp-end (point-min)))
|
||||
start limit 1
|
||||
(ignore-errors
|
||||
(forward-char -10000))
|
||||
(forward-line 0)
|
||||
(save-excursion
|
||||
;; Before, we used backward search, but it matches non-greedily, and
|
||||
;; that forced us to use the "beginning/end of word" anchors in
|
||||
;; `company-dabbrev--make-regexp'. It's also about 2x slower.
|
||||
(while (and (not (input-pending-p))
|
||||
(re-search-forward regexp tmp-end t))
|
||||
(if (and ignore-comments (save-match-data (company-in-string-or-comment)))
|
||||
(re-search-forward "\\s>\\|\\s!\\|\\s\"" tmp-end t)
|
||||
(maybe-collect-match))))
|
||||
(setq tmp-end (point))))
|
||||
(goto-char (or pos (point-min)))
|
||||
;; Search after pos.
|
||||
(company-dabbrev--time-limit-while (and (not (input-pending-p))
|
||||
(re-search-forward regexp nil t))
|
||||
start limit 25
|
||||
(if (and ignore-comments (save-match-data (company-in-string-or-comment)))
|
||||
(re-search-forward "\\s>\\|\\s!\\|\\s\"" nil t)
|
||||
(maybe-collect-match)))
|
||||
symbols)))
|
||||
|
||||
(defun company-dabbrev--search (regexp &optional limit other-buffer-modes
|
||||
ignore-comments)
|
||||
(let* ((start (current-time))
|
||||
(symbols (company-dabbrev--search-buffer regexp (point) nil start limit
|
||||
ignore-comments)))
|
||||
(when other-buffer-modes
|
||||
(cl-dolist (buffer (delq (current-buffer) (buffer-list)))
|
||||
(unless (if (stringp company-dabbrev-ignore-buffers)
|
||||
(string-match-p company-dabbrev-ignore-buffers
|
||||
(buffer-name buffer))
|
||||
(funcall company-dabbrev-ignore-buffers buffer))
|
||||
(with-current-buffer buffer
|
||||
(when (or (eq other-buffer-modes 'all)
|
||||
(apply #'derived-mode-p other-buffer-modes))
|
||||
(setq symbols
|
||||
(company-dabbrev--search-buffer regexp nil symbols start
|
||||
limit ignore-comments)))))
|
||||
(and limit
|
||||
(> (float-time (time-since start)) limit)
|
||||
(cl-return))))
|
||||
symbols))
|
||||
|
||||
(defun company-dabbrev--prefix ()
|
||||
;; Not in the middle of a word.
|
||||
(unless (looking-at company-dabbrev-char-regexp)
|
||||
;; Emacs can't do greedy backward-search.
|
||||
(company-grab-line (format "\\(?:^\\| \\)[^ ]*?\\(\\(?:%s\\)*\\)"
|
||||
company-dabbrev-char-regexp)
|
||||
1)))
|
||||
|
||||
(defun company-dabbrev--filter (prefix candidates)
|
||||
(let ((completion-ignore-case company-dabbrev-ignore-case))
|
||||
(all-completions prefix candidates)))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-dabbrev (command &optional arg &rest ignored)
|
||||
"dabbrev-like `company-mode' completion backend."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-dabbrev))
|
||||
(prefix (company-dabbrev--prefix))
|
||||
(candidates
|
||||
(let* ((case-fold-search company-dabbrev-ignore-case)
|
||||
(words (company-dabbrev--search (company-dabbrev--make-regexp)
|
||||
company-dabbrev-time-limit
|
||||
(pcase company-dabbrev-other-buffers
|
||||
(`t (list major-mode))
|
||||
(`all `all))))
|
||||
(downcase-p (if (eq company-dabbrev-downcase 'case-replace)
|
||||
case-replace
|
||||
company-dabbrev-downcase)))
|
||||
(setq words (company-dabbrev--filter arg words))
|
||||
(if downcase-p
|
||||
(mapcar 'downcase words)
|
||||
words)))
|
||||
(ignore-case company-dabbrev-ignore-case)
|
||||
(duplicates t)))
|
||||
|
||||
(provide 'company-dabbrev)
|
||||
;;; company-dabbrev.el ends here
|
Binary file not shown.
|
@ -0,0 +1,186 @@
|
|||
;;; company-eclim.el --- company-mode completion backend for Eclim
|
||||
|
||||
;; Copyright (C) 2009, 2011, 2013, 2015 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Using `emacs-eclim' together with (or instead of) this backend is
|
||||
;; recommended, as it allows you to use other Eclim features.
|
||||
;;
|
||||
;; The alternative backend provided by `emacs-eclim' uses `yasnippet'
|
||||
;; instead of `company-template' to expand function calls, and it supports
|
||||
;; some languages other than Java.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'company-template)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-eclim nil
|
||||
"Completion backend for Eclim."
|
||||
:group 'company)
|
||||
|
||||
(defun company-eclim-executable-find ()
|
||||
(let (file)
|
||||
(cl-dolist (eclipse-root '("/Applications/eclipse" "/usr/lib/eclipse"
|
||||
"/usr/local/lib/eclipse"))
|
||||
(and (file-exists-p (setq file (expand-file-name "plugins" eclipse-root)))
|
||||
(setq file (car (last (directory-files file t "^org.eclim_"))))
|
||||
(file-exists-p (setq file (expand-file-name "bin/eclim" file)))
|
||||
(cl-return file)))))
|
||||
|
||||
(defcustom company-eclim-executable
|
||||
(or (bound-and-true-p eclim-executable)
|
||||
(executable-find "eclim")
|
||||
(company-eclim-executable-find))
|
||||
"Location of eclim executable."
|
||||
:type 'file)
|
||||
|
||||
(defcustom company-eclim-auto-save t
|
||||
"Determines whether to save the buffer when retrieving completions.
|
||||
eclim can only complete correctly when the buffer has been saved."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(const :tag "On" t)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defvar-local company-eclim--project-dir 'unknown)
|
||||
|
||||
(defvar-local company-eclim--project-name nil)
|
||||
|
||||
(declare-function json-read "json")
|
||||
(defvar json-array-type)
|
||||
|
||||
(defun company-eclim--call-process (&rest args)
|
||||
(let ((coding-system-for-read 'utf-8)
|
||||
res)
|
||||
(require 'json)
|
||||
(with-temp-buffer
|
||||
(if (= 0 (setq res (apply 'call-process company-eclim-executable nil t nil
|
||||
"-command" args)))
|
||||
(let ((json-array-type 'list))
|
||||
(goto-char (point-min))
|
||||
(unless (eobp)
|
||||
(json-read)))
|
||||
(message "Company-eclim command failed with error %d:\n%s" res
|
||||
(buffer-substring (point-min) (point-max)))
|
||||
nil))))
|
||||
|
||||
(defun company-eclim--project-list ()
|
||||
(company-eclim--call-process "project_list"))
|
||||
|
||||
(defun company-eclim--project-dir ()
|
||||
(if (eq company-eclim--project-dir 'unknown)
|
||||
(let ((dir (locate-dominating-file buffer-file-name ".project")))
|
||||
(when dir
|
||||
(setq company-eclim--project-dir
|
||||
(directory-file-name
|
||||
(expand-file-name dir)))))
|
||||
company-eclim--project-dir))
|
||||
|
||||
(defun company-eclim--project-name ()
|
||||
(or company-eclim--project-name
|
||||
(let ((dir (company-eclim--project-dir)))
|
||||
(when dir
|
||||
(setq company-eclim--project-name
|
||||
(cl-loop for project in (company-eclim--project-list)
|
||||
when (equal (cdr (assoc 'path project)) dir)
|
||||
return (cdr (assoc 'name project))))))))
|
||||
|
||||
(defun company-eclim--candidates (prefix)
|
||||
(interactive "d")
|
||||
(let ((project-file (file-relative-name buffer-file-name
|
||||
(company-eclim--project-dir)))
|
||||
completions)
|
||||
(when company-eclim-auto-save
|
||||
(when (buffer-modified-p)
|
||||
(basic-save-buffer))
|
||||
;; FIXME: Sometimes this isn't finished when we complete.
|
||||
(company-eclim--call-process "java_src_update"
|
||||
"-p" (company-eclim--project-name)
|
||||
"-f" project-file))
|
||||
(dolist (item (cdr (assoc 'completions
|
||||
(company-eclim--call-process
|
||||
"java_complete" "-p" (company-eclim--project-name)
|
||||
"-f" project-file
|
||||
"-o" (number-to-string
|
||||
(company-eclim--search-point prefix))
|
||||
"-e" "utf-8"
|
||||
"-l" "standard"))))
|
||||
(let* ((meta (cdr (assoc 'info item)))
|
||||
(completion meta))
|
||||
(when (string-match " ?[(:-]" completion)
|
||||
(setq completion (substring completion 0 (match-beginning 0))))
|
||||
(put-text-property 0 1 'meta meta completion)
|
||||
(push completion completions)))
|
||||
(let ((completion-ignore-case nil))
|
||||
(all-completions prefix completions))))
|
||||
|
||||
(defun company-eclim--search-point (prefix)
|
||||
(if (or (cl-plusp (length prefix)) (eq (char-before) ?.))
|
||||
(1- (point))
|
||||
(point)))
|
||||
|
||||
(defun company-eclim--meta (candidate)
|
||||
(get-text-property 0 'meta candidate))
|
||||
|
||||
(defun company-eclim--annotation (candidate)
|
||||
(let ((meta (company-eclim--meta candidate)))
|
||||
(when (string-match "\\(([^-]*\\) -" meta)
|
||||
(substring meta (match-beginning 1) (match-end 1)))))
|
||||
|
||||
(defun company-eclim--prefix ()
|
||||
(let ((prefix (company-grab-symbol)))
|
||||
(when prefix
|
||||
;; Completion candidates for annotations don't include '@'.
|
||||
(when (eq ?@ (string-to-char prefix))
|
||||
(setq prefix (substring prefix 1)))
|
||||
prefix)))
|
||||
|
||||
(defun company-eclim (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for Eclim.
|
||||
Eclim provides access to Eclipse Java IDE features for other editors.
|
||||
|
||||
Eclim version 1.7.13 or newer (?) is required.
|
||||
|
||||
Completions only work correctly when the buffer has been saved.
|
||||
`company-eclim-auto-save' determines whether to do this automatically."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-eclim))
|
||||
(prefix (and (derived-mode-p 'java-mode 'jde-mode)
|
||||
buffer-file-name
|
||||
company-eclim-executable
|
||||
(company-eclim--project-name)
|
||||
(not (company-in-string-or-comment))
|
||||
(or (company-eclim--prefix) 'stop)))
|
||||
(candidates (company-eclim--candidates arg))
|
||||
(meta (company-eclim--meta arg))
|
||||
;; because "" doesn't return everything
|
||||
(no-cache (equal arg ""))
|
||||
(annotation (company-eclim--annotation arg))
|
||||
(post-completion (let ((anno (company-eclim--annotation arg)))
|
||||
(when anno
|
||||
(insert anno)
|
||||
(company-template-c-like-templatify anno))))))
|
||||
|
||||
(provide 'company-eclim)
|
||||
;;; company-eclim.el ends here
|
Binary file not shown.
|
@ -0,0 +1,226 @@
|
|||
;;; company-elisp.el --- company-mode completion backend for Emacs Lisp -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2009, 2011-2013, 2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; In newer versions of Emacs, company-capf is used instead.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
(require 'help-mode)
|
||||
(require 'find-func)
|
||||
|
||||
(defgroup company-elisp nil
|
||||
"Completion backend for Emacs Lisp."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-elisp-detect-function-context t
|
||||
"If enabled, offer Lisp functions only in appropriate contexts.
|
||||
Functions are offered for completion only after ' and \(."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(const :tag "On" t)))
|
||||
|
||||
(defcustom company-elisp-show-locals-first t
|
||||
"If enabled, locally bound variables and functions are displayed
|
||||
first in the candidates list."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(const :tag "On" t)))
|
||||
|
||||
(defun company-elisp--prefix ()
|
||||
(let ((prefix (company-grab-symbol)))
|
||||
(if prefix
|
||||
(when (if (company-in-string-or-comment)
|
||||
(= (char-before (- (point) (length prefix))) ?`)
|
||||
(company-elisp--should-complete))
|
||||
prefix)
|
||||
'stop)))
|
||||
|
||||
(defun company-elisp--predicate (symbol)
|
||||
(or (boundp symbol)
|
||||
(fboundp symbol)
|
||||
(facep symbol)
|
||||
(featurep symbol)))
|
||||
|
||||
(defun company-elisp--fns-regexp (&rest names)
|
||||
(concat "\\_<\\(?:cl-\\)?" (regexp-opt names) "\\*?\\_>"))
|
||||
|
||||
(defvar company-elisp-parse-limit 30)
|
||||
(defvar company-elisp-parse-depth 100)
|
||||
|
||||
(defvar company-elisp-defun-names '("defun" "defmacro" "defsubst"))
|
||||
|
||||
(defvar company-elisp-var-binding-regexp
|
||||
(apply #'company-elisp--fns-regexp "let" "lambda" "lexical-let"
|
||||
company-elisp-defun-names)
|
||||
"Regular expression matching head of a multiple variable bindings form.")
|
||||
|
||||
(defvar company-elisp-var-binding-regexp-1
|
||||
(company-elisp--fns-regexp "dolist" "dotimes")
|
||||
"Regular expression matching head of a form with one variable binding.")
|
||||
|
||||
(defvar company-elisp-fun-binding-regexp
|
||||
(company-elisp--fns-regexp "flet" "labels")
|
||||
"Regular expression matching head of a function bindings form.")
|
||||
|
||||
(defvar company-elisp-defuns-regexp
|
||||
(concat "([ \t\n]*"
|
||||
(apply #'company-elisp--fns-regexp company-elisp-defun-names)))
|
||||
|
||||
(defun company-elisp--should-complete ()
|
||||
(let ((start (point))
|
||||
(depth (car (syntax-ppss))))
|
||||
(not
|
||||
(when (> depth 0)
|
||||
(save-excursion
|
||||
(up-list (- depth))
|
||||
(when (looking-at company-elisp-defuns-regexp)
|
||||
(forward-char)
|
||||
(forward-sexp 1)
|
||||
(unless (= (point) start)
|
||||
(condition-case nil
|
||||
(let ((args-end (scan-sexps (point) 2)))
|
||||
(or (null args-end)
|
||||
(> args-end start)))
|
||||
(scan-error
|
||||
t)))))))))
|
||||
|
||||
(defun company-elisp--locals (prefix functions-p)
|
||||
(let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
|
||||
"\\(?:\\sw\\|\\s_\\)*\\_>\\)"))
|
||||
(pos (point))
|
||||
res)
|
||||
(condition-case nil
|
||||
(save-excursion
|
||||
(dotimes (_ company-elisp-parse-depth)
|
||||
(up-list -1)
|
||||
(save-excursion
|
||||
(when (eq (char-after) ?\()
|
||||
(forward-char 1)
|
||||
(when (ignore-errors
|
||||
(save-excursion (forward-list)
|
||||
(<= (point) pos)))
|
||||
(skip-chars-forward " \t\n")
|
||||
(cond
|
||||
((looking-at (if functions-p
|
||||
company-elisp-fun-binding-regexp
|
||||
company-elisp-var-binding-regexp))
|
||||
(down-list 1)
|
||||
(condition-case nil
|
||||
(dotimes (_ company-elisp-parse-limit)
|
||||
(save-excursion
|
||||
(when (looking-at "[ \t\n]*(")
|
||||
(down-list 1))
|
||||
(when (looking-at regexp)
|
||||
(cl-pushnew (match-string-no-properties 1) res)))
|
||||
(forward-sexp))
|
||||
(scan-error nil)))
|
||||
((unless functions-p
|
||||
(looking-at company-elisp-var-binding-regexp-1))
|
||||
(down-list 1)
|
||||
(when (looking-at regexp)
|
||||
(cl-pushnew (match-string-no-properties 1) res)))))))))
|
||||
(scan-error nil))
|
||||
res))
|
||||
|
||||
(defun company-elisp-candidates (prefix)
|
||||
(let* ((predicate (company-elisp--candidates-predicate prefix))
|
||||
(locals (company-elisp--locals prefix (eq predicate 'fboundp)))
|
||||
(globals (company-elisp--globals prefix predicate))
|
||||
(locals (cl-loop for local in locals
|
||||
when (not (member local globals))
|
||||
collect local)))
|
||||
(if company-elisp-show-locals-first
|
||||
(append (sort locals 'string<)
|
||||
(sort globals 'string<))
|
||||
(append locals globals))))
|
||||
|
||||
(defun company-elisp--globals (prefix predicate)
|
||||
(all-completions prefix obarray predicate))
|
||||
|
||||
(defun company-elisp--candidates-predicate (prefix)
|
||||
(let* ((completion-ignore-case nil)
|
||||
(beg (- (point) (length prefix)))
|
||||
(before (char-before beg)))
|
||||
(if (and company-elisp-detect-function-context
|
||||
(not (memq before '(?' ?`))))
|
||||
(if (and (eq before ?\()
|
||||
(not
|
||||
(save-excursion
|
||||
(ignore-errors
|
||||
(goto-char (1- beg))
|
||||
(or (company-elisp--before-binding-varlist-p)
|
||||
(progn
|
||||
(up-list -1)
|
||||
(company-elisp--before-binding-varlist-p)))))))
|
||||
'fboundp
|
||||
'boundp)
|
||||
'company-elisp--predicate)))
|
||||
|
||||
(defun company-elisp--before-binding-varlist-p ()
|
||||
(save-excursion
|
||||
(and (prog1 (search-backward "(")
|
||||
(forward-char 1))
|
||||
(looking-at company-elisp-var-binding-regexp))))
|
||||
|
||||
(defun company-elisp--doc (symbol)
|
||||
(let* ((symbol (intern symbol))
|
||||
(doc (if (fboundp symbol)
|
||||
(documentation symbol t)
|
||||
(documentation-property symbol 'variable-documentation t))))
|
||||
(and (stringp doc)
|
||||
(string-match ".*$" doc)
|
||||
(match-string 0 doc))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-elisp (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for Emacs Lisp."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-elisp))
|
||||
(prefix (and (derived-mode-p 'emacs-lisp-mode 'inferior-emacs-lisp-mode)
|
||||
(company-elisp--prefix)))
|
||||
(candidates (company-elisp-candidates arg))
|
||||
(sorted company-elisp-show-locals-first)
|
||||
(meta (company-elisp--doc arg))
|
||||
(doc-buffer (let ((symbol (intern arg)))
|
||||
(save-window-excursion
|
||||
(ignore-errors
|
||||
(cond
|
||||
((fboundp symbol) (describe-function symbol))
|
||||
((boundp symbol) (describe-variable symbol))
|
||||
((featurep symbol) (describe-package symbol))
|
||||
((facep symbol) (describe-face symbol))
|
||||
(t (signal 'user-error nil)))
|
||||
(help-buffer)))))
|
||||
(location (let ((sym (intern arg)))
|
||||
(cond
|
||||
((fboundp sym) (find-definition-noselect sym nil))
|
||||
((boundp sym) (find-definition-noselect sym 'defvar))
|
||||
((featurep sym) (cons (find-file-noselect (find-library-name
|
||||
(symbol-name sym)))
|
||||
0))
|
||||
((facep sym) (find-definition-noselect sym 'defface)))))))
|
||||
|
||||
(provide 'company-elisp)
|
||||
;;; company-elisp.el ends here
|
Binary file not shown.
|
@ -0,0 +1,108 @@
|
|||
;;; company-etags.el --- company-mode completion backend for etags
|
||||
|
||||
;; Copyright (C) 2009-2011, 2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
(require 'etags)
|
||||
|
||||
(defgroup company-etags nil
|
||||
"Completion backend for etags."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-etags-use-main-table-list t
|
||||
"Always search `tags-table-list' if set.
|
||||
If this is disabled, `company-etags' will try to find the one table for each
|
||||
buffer automatically."
|
||||
:type '(choice (const :tag "off" nil)
|
||||
(const :tag "on" t)))
|
||||
|
||||
(defcustom company-etags-ignore-case nil
|
||||
"Non-nil to ignore case in completion candidates."
|
||||
:type 'boolean
|
||||
:package-version '(company . "0.7.3"))
|
||||
|
||||
(defcustom company-etags-everywhere nil
|
||||
"Non-nil to offer completions in comments and strings.
|
||||
Set it to t or to a list of major modes."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(const :tag "Any supported mode" t)
|
||||
(repeat :tag "Some major modes"
|
||||
(symbol :tag "Major mode")))
|
||||
:package-version '(company . "0.9.0"))
|
||||
|
||||
(defvar company-etags-modes '(prog-mode c-mode objc-mode c++-mode java-mode
|
||||
jde-mode pascal-mode perl-mode python-mode))
|
||||
|
||||
(defvar-local company-etags-buffer-table 'unknown)
|
||||
|
||||
(defun company-etags-find-table ()
|
||||
(let ((file (expand-file-name
|
||||
"TAGS"
|
||||
(locate-dominating-file (or buffer-file-name
|
||||
default-directory)
|
||||
"TAGS"))))
|
||||
(when (and file (file-regular-p file))
|
||||
(list file))))
|
||||
|
||||
(defun company-etags-buffer-table ()
|
||||
(or (and company-etags-use-main-table-list tags-table-list)
|
||||
(if (eq company-etags-buffer-table 'unknown)
|
||||
(setq company-etags-buffer-table (company-etags-find-table))
|
||||
company-etags-buffer-table)))
|
||||
|
||||
(defun company-etags--candidates (prefix)
|
||||
(let ((tags-table-list (company-etags-buffer-table))
|
||||
(tags-file-name tags-file-name)
|
||||
(completion-ignore-case company-etags-ignore-case))
|
||||
(and (or tags-file-name tags-table-list)
|
||||
(fboundp 'tags-completion-table)
|
||||
(save-excursion
|
||||
(visit-tags-table-buffer)
|
||||
(all-completions prefix (tags-completion-table))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-etags (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for etags."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-etags))
|
||||
(prefix (and (apply #'derived-mode-p company-etags-modes)
|
||||
(or (eq t company-etags-everywhere)
|
||||
(apply #'derived-mode-p company-etags-everywhere)
|
||||
(not (company-in-string-or-comment)))
|
||||
(company-etags-buffer-table)
|
||||
(or (company-grab-symbol) 'stop)))
|
||||
(candidates (company-etags--candidates arg))
|
||||
(location (let ((tags-table-list (company-etags-buffer-table)))
|
||||
(when (fboundp 'find-tag-noselect)
|
||||
(save-excursion
|
||||
(let ((buffer (find-tag-noselect arg)))
|
||||
(cons buffer (with-current-buffer buffer (point))))))))
|
||||
(ignore-case company-etags-ignore-case)))
|
||||
|
||||
(provide 'company-etags)
|
||||
;;; company-etags.el ends here
|
Binary file not shown.
|
@ -0,0 +1,148 @@
|
|||
;;; company-files.el --- company-mode completion backend for file names
|
||||
|
||||
;; Copyright (C) 2009-2011, 2014-2015 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-files nil
|
||||
"Completion backend for file names."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-files-exclusions nil
|
||||
"File name extensions and directory names to ignore.
|
||||
The values should use the same format as `completion-ignored-extensions'."
|
||||
:type '(const string)
|
||||
:package-version '(company . "0.9.1"))
|
||||
|
||||
(defun company-files--directory-files (dir prefix)
|
||||
;; Don't use directory-files. It produces directories without trailing /.
|
||||
(condition-case err
|
||||
(let ((comp (sort (file-name-all-completions prefix dir)
|
||||
(lambda (s1 s2) (string-lessp (downcase s1) (downcase s2))))))
|
||||
(when company-files-exclusions
|
||||
(setq comp (company-files--exclusions-filtered comp)))
|
||||
(if (equal prefix "")
|
||||
(delete "../" (delete "./" comp))
|
||||
comp))
|
||||
(file-error nil)))
|
||||
|
||||
(defun company-files--exclusions-filtered (completions)
|
||||
(let* ((dir-exclusions (cl-delete-if-not #'company-files--trailing-slash-p
|
||||
company-files-exclusions))
|
||||
(file-exclusions (cl-set-difference company-files-exclusions
|
||||
dir-exclusions)))
|
||||
(cl-loop for c in completions
|
||||
unless (if (company-files--trailing-slash-p c)
|
||||
(member c dir-exclusions)
|
||||
(cl-find-if (lambda (exclusion)
|
||||
(string-suffix-p exclusion c))
|
||||
file-exclusions))
|
||||
collect c)))
|
||||
|
||||
(defvar company-files--regexps
|
||||
(let* ((root (if (eq system-type 'windows-nt)
|
||||
"[a-zA-Z]:/"
|
||||
"/"))
|
||||
(begin (concat "\\(?:\\.\\{1,2\\}/\\|~/\\|" root "\\)")))
|
||||
(list (concat "\"\\(" begin "[^\"\n]*\\)")
|
||||
(concat "\'\\(" begin "[^\'\n]*\\)")
|
||||
(concat "\\(?:[ \t=]\\|^\\)\\(" begin "[^ \t\n]*\\)"))))
|
||||
|
||||
(defun company-files--grab-existing-name ()
|
||||
;; Grab the file name.
|
||||
;; When surrounded with quotes, it can include spaces.
|
||||
(let (file dir)
|
||||
(and (cl-dolist (regexp company-files--regexps)
|
||||
(when (setq file (company-grab-line regexp 1))
|
||||
(cl-return file)))
|
||||
(company-files--connected-p file)
|
||||
(setq dir (file-name-directory file))
|
||||
(not (string-match "//" dir))
|
||||
(file-exists-p dir)
|
||||
file)))
|
||||
|
||||
(defun company-files--connected-p (file)
|
||||
(or (not (file-remote-p file))
|
||||
(file-remote-p file nil t)))
|
||||
|
||||
(defun company-files--trailing-slash-p (file)
|
||||
;; `file-directory-p' is very expensive on remotes. We are relying on
|
||||
;; `file-name-all-completions' returning directories with trailing / instead.
|
||||
(let ((len (length file)))
|
||||
(and (> len 0) (eq (aref file (1- len)) ?/))))
|
||||
|
||||
(defvar company-files--completion-cache nil)
|
||||
|
||||
(defun company-files--complete (prefix)
|
||||
(let* ((dir (file-name-directory prefix))
|
||||
(file (file-name-nondirectory prefix))
|
||||
(key (list file
|
||||
(expand-file-name dir)
|
||||
(nth 5 (file-attributes dir))))
|
||||
(completion-ignore-case read-file-name-completion-ignore-case))
|
||||
(unless (company-file--keys-match-p key (car company-files--completion-cache))
|
||||
(let* ((candidates (mapcar (lambda (f) (concat dir f))
|
||||
(company-files--directory-files dir file)))
|
||||
(directories (unless (file-remote-p dir)
|
||||
(cl-remove-if-not (lambda (f)
|
||||
(and (company-files--trailing-slash-p f)
|
||||
(not (file-remote-p f))
|
||||
(company-files--connected-p f)))
|
||||
candidates)))
|
||||
(children (and directories
|
||||
(cl-mapcan (lambda (d)
|
||||
(mapcar (lambda (c) (concat d c))
|
||||
(company-files--directory-files d "")))
|
||||
directories))))
|
||||
(setq company-files--completion-cache
|
||||
(cons key (append candidates children)))))
|
||||
(all-completions prefix
|
||||
(cdr company-files--completion-cache))))
|
||||
|
||||
(defun company-file--keys-match-p (new old)
|
||||
(and (equal (cdr old) (cdr new))
|
||||
(string-prefix-p (car old) (car new))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-files (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend existing file names.
|
||||
Completions works for proper absolute and relative files paths.
|
||||
File paths with spaces are only supported inside strings."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-files))
|
||||
(prefix (company-files--grab-existing-name))
|
||||
(candidates (company-files--complete arg))
|
||||
(location (cons (dired-noselect
|
||||
(file-name-directory (directory-file-name arg))) 1))
|
||||
(post-completion (when (company-files--trailing-slash-p arg)
|
||||
(delete-char -1)))
|
||||
(sorted t)
|
||||
(no-cache t)))
|
||||
|
||||
(provide 'company-files)
|
||||
;;; company-files.el ends here
|
Binary file not shown.
|
@ -0,0 +1,117 @@
|
|||
;;; company-gtags.el --- company-mode completion backend for GNU Global
|
||||
|
||||
;; Copyright (C) 2009-2011, 2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'company-template)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-gtags nil
|
||||
"Completion backend for GNU Global."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-gtags-executable
|
||||
(executable-find "global")
|
||||
"Location of GNU global executable."
|
||||
:type 'string)
|
||||
|
||||
(define-obsolete-variable-alias
|
||||
'company-gtags-gnu-global-program-name
|
||||
'company-gtags-executable "earlier")
|
||||
|
||||
(defcustom company-gtags-insert-arguments t
|
||||
"When non-nil, insert function arguments as a template after completion."
|
||||
:type 'boolean
|
||||
:package-version '(company . "0.8.1"))
|
||||
|
||||
(defvar-local company-gtags--tags-available-p 'unknown)
|
||||
|
||||
(defcustom company-gtags-modes '(prog-mode jde-mode)
|
||||
"Modes that use `company-gtags'.
|
||||
In all these modes (and their derivatives) `company-gtags' will perform
|
||||
completion."
|
||||
:type '(repeat (symbol :tag "Major mode"))
|
||||
:package-version '(company . "0.8.4"))
|
||||
|
||||
(defun company-gtags--tags-available-p ()
|
||||
(if (eq company-gtags--tags-available-p 'unknown)
|
||||
(setq company-gtags--tags-available-p
|
||||
(locate-dominating-file buffer-file-name "GTAGS"))
|
||||
company-gtags--tags-available-p))
|
||||
|
||||
(defun company-gtags--fetch-tags (prefix)
|
||||
(with-temp-buffer
|
||||
(let (tags)
|
||||
(when (= 0 (process-file company-gtags-executable nil
|
||||
;; "-T" goes through all the tag files listed in GTAGSLIBPATH
|
||||
(list (current-buffer) nil) nil "-xGqT" (concat "^" prefix)))
|
||||
(goto-char (point-min))
|
||||
(cl-loop while
|
||||
(re-search-forward (concat
|
||||
"^"
|
||||
"\\([^ ]*\\)" ;; completion
|
||||
"[ \t]+\\([[:digit:]]+\\)" ;; linum
|
||||
"[ \t]+\\([^ \t]+\\)" ;; file
|
||||
"[ \t]+\\(.*\\)" ;; definition
|
||||
"$"
|
||||
) nil t)
|
||||
collect
|
||||
(propertize (match-string 1)
|
||||
'meta (match-string 4)
|
||||
'location (cons (expand-file-name (match-string 3))
|
||||
(string-to-number (match-string 2)))
|
||||
))))))
|
||||
|
||||
(defun company-gtags--annotation (arg)
|
||||
(let ((meta (get-text-property 0 'meta arg)))
|
||||
(when (string-match (concat arg "\\((.*)\\).*") meta)
|
||||
(match-string 1 meta))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-gtags (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for GNU Global."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-gtags))
|
||||
(prefix (and company-gtags-executable
|
||||
buffer-file-name
|
||||
(apply #'derived-mode-p company-gtags-modes)
|
||||
(not (company-in-string-or-comment))
|
||||
(company-gtags--tags-available-p)
|
||||
(or (company-grab-symbol) 'stop)))
|
||||
(candidates (company-gtags--fetch-tags arg))
|
||||
(sorted t)
|
||||
(duplicates t)
|
||||
(annotation (company-gtags--annotation arg))
|
||||
(meta (get-text-property 0 'meta arg))
|
||||
(location (get-text-property 0 'location arg))
|
||||
(post-completion (let ((anno (company-gtags--annotation arg)))
|
||||
(when (and company-gtags-insert-arguments anno)
|
||||
(insert anno)
|
||||
(company-template-c-like-templatify anno))))))
|
||||
|
||||
(provide 'company-gtags)
|
||||
;;; company-gtags.el ends here
|
Binary file not shown.
|
@ -0,0 +1,82 @@
|
|||
;;; company-ispell.el --- company-mode completion backend using Ispell
|
||||
|
||||
;; Copyright (C) 2009-2011, 2013-2016 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
(require 'ispell)
|
||||
|
||||
(defgroup company-ispell nil
|
||||
"Completion backend using Ispell."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-ispell-dictionary nil
|
||||
"Dictionary to use for `company-ispell'.
|
||||
If nil, use `ispell-complete-word-dict'."
|
||||
:type '(choice (const :tag "default (nil)" nil)
|
||||
(file :tag "dictionary" t)))
|
||||
|
||||
(defvar company-ispell-available 'unknown)
|
||||
|
||||
(defalias 'company-ispell--lookup-words
|
||||
(if (fboundp 'ispell-lookup-words)
|
||||
'ispell-lookup-words
|
||||
'lookup-words))
|
||||
|
||||
(defun company-ispell-available ()
|
||||
(when (eq company-ispell-available 'unknown)
|
||||
(condition-case err
|
||||
(progn
|
||||
(company-ispell--lookup-words "WHATEVER")
|
||||
(setq company-ispell-available t))
|
||||
(error
|
||||
(message "Company: ispell-look-command not found")
|
||||
(setq company-ispell-available nil))))
|
||||
company-ispell-available)
|
||||
|
||||
;;;###autoload
|
||||
(defun company-ispell (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend using Ispell."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-ispell))
|
||||
(prefix (when (company-ispell-available)
|
||||
(company-grab-word)))
|
||||
(candidates
|
||||
(let ((words (company-ispell--lookup-words
|
||||
arg
|
||||
(or company-ispell-dictionary ispell-complete-word-dict)))
|
||||
(completion-ignore-case t))
|
||||
(if (string= arg "")
|
||||
;; Small optimization.
|
||||
words
|
||||
;; Work around issue #284.
|
||||
(all-completions arg words))))
|
||||
(sorted t)
|
||||
(ignore-case 'keep-prefix)))
|
||||
|
||||
(provide 'company-ispell)
|
||||
;;; company-ispell.el ends here
|
Binary file not shown.
|
@ -0,0 +1,305 @@
|
|||
;;; company-keywords.el --- A company backend for programming language keywords
|
||||
|
||||
;; Copyright (C) 2009-2011, 2016 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defun company-keywords-upper-lower (&rest lst)
|
||||
;; Upcase order is different for _.
|
||||
(nconc (sort (mapcar 'upcase lst) 'string<) lst))
|
||||
|
||||
(defvar company-keywords-alist
|
||||
;; Please contribute corrections or additions.
|
||||
`((c++-mode
|
||||
"alignas" "alignof" "asm" "auto" "bool" "break" "case" "catch" "char"
|
||||
"char16_t" "char32_t" "class" "const" "const_cast" "constexpr" "continue"
|
||||
"decltype" "default" "delete" "do" "double" "dynamic_cast" "else" "enum"
|
||||
"explicit" "export" "extern" "false" "final" "float" "for" "friend"
|
||||
"goto" "if" "inline" "int" "long" "mutable" "namespace" "new" "noexcept"
|
||||
"nullptr" "operator" "override"
|
||||
"private" "protected" "public" "register" "reinterpret_cast"
|
||||
"return" "short" "signed" "sizeof" "static" "static_assert"
|
||||
"static_cast" "struct" "switch" "template" "this" "thread_local"
|
||||
"throw" "true" "try" "typedef" "typeid" "typename"
|
||||
"union" "unsigned" "using" "virtual" "void" "volatile" "wchar_t" "while")
|
||||
(c-mode
|
||||
"auto" "break" "case" "char" "const" "continue" "default" "do"
|
||||
"double" "else" "enum" "extern" "float" "for" "goto" "if" "int" "long"
|
||||
"register" "return" "short" "signed" "sizeof" "static" "struct"
|
||||
"switch" "typedef" "union" "unsigned" "void" "volatile" "while")
|
||||
(csharp-mode
|
||||
"abstract" "add" "alias" "as" "base" "bool" "break" "byte" "case"
|
||||
"catch" "char" "checked" "class" "const" "continue" "decimal" "default"
|
||||
"delegate" "do" "double" "else" "enum" "event" "explicit" "extern"
|
||||
"false" "finally" "fixed" "float" "for" "foreach" "get" "global" "goto"
|
||||
"if" "implicit" "in" "int" "interface" "internal" "is" "lock" "long"
|
||||
"namespace" "new" "null" "object" "operator" "out" "override" "params"
|
||||
"partial" "private" "protected" "public" "readonly" "ref" "remove"
|
||||
"return" "sbyte" "sealed" "set" "short" "sizeof" "stackalloc" "static"
|
||||
"string" "struct" "switch" "this" "throw" "true" "try" "typeof" "uint"
|
||||
"ulong" "unchecked" "unsafe" "ushort" "using" "value" "var" "virtual"
|
||||
"void" "volatile" "where" "while" "yield")
|
||||
(d-mode
|
||||
;; from http://www.digitalmars.com/d/2.0/lex.html
|
||||
"abstract" "alias" "align" "asm"
|
||||
"assert" "auto" "body" "bool" "break" "byte" "case" "cast" "catch"
|
||||
"cdouble" "cent" "cfloat" "char" "class" "const" "continue" "creal"
|
||||
"dchar" "debug" "default" "delegate" "delete" "deprecated" "do"
|
||||
"double" "else" "enum" "export" "extern" "false" "final" "finally"
|
||||
"float" "for" "foreach" "foreach_reverse" "function" "goto" "idouble"
|
||||
"if" "ifloat" "import" "in" "inout" "int" "interface" "invariant"
|
||||
"ireal" "is" "lazy" "long" "macro" "mixin" "module" "new" "nothrow"
|
||||
"null" "out" "override" "package" "pragma" "private" "protected"
|
||||
"public" "pure" "real" "ref" "return" "scope" "short" "static" "struct"
|
||||
"super" "switch" "synchronized" "template" "this" "throw" "true" "try"
|
||||
"typedef" "typeid" "typeof" "ubyte" "ucent" "uint" "ulong" "union"
|
||||
"unittest" "ushort" "version" "void" "volatile" "wchar" "while" "with")
|
||||
(f90-mode .
|
||||
;; from f90.el
|
||||
;; ".AND." ".GE." ".GT." ".LT." ".LE." ".NE." ".OR." ".TRUE." ".FALSE."
|
||||
,(company-keywords-upper-lower
|
||||
"abs" "abstract" "achar" "acos" "adjustl" "adjustr" "aimag" "aint"
|
||||
"align" "all" "all_prefix" "all_scatter" "all_suffix" "allocatable"
|
||||
"allocate" "allocated" "and" "anint" "any" "any_prefix" "any_scatter"
|
||||
"any_suffix" "asin" "assign" "assignment" "associate" "associated"
|
||||
"asynchronous" "atan" "atan2" "backspace" "bind" "bit_size" "block"
|
||||
"btest" "c_alert" "c_associated" "c_backspace" "c_bool"
|
||||
"c_carriage_return" "c_char" "c_double" "c_double_complex" "c_f_pointer"
|
||||
"c_f_procpointer" "c_float" "c_float_complex" "c_form_feed" "c_funloc"
|
||||
"c_funptr" "c_horizontal_tab" "c_int" "c_int16_t" "c_int32_t" "c_int64_t"
|
||||
"c_int8_t" "c_int_fast16_t" "c_int_fast32_t" "c_int_fast64_t"
|
||||
"c_int_fast8_t" "c_int_least16_t" "c_int_least32_t" "c_int_least64_t"
|
||||
"c_int_least8_t" "c_intmax_t" "c_intptr_t" "c_loc" "c_long"
|
||||
"c_long_double" "c_long_double_complex" "c_long_long" "c_new_line"
|
||||
"c_null_char" "c_null_funptr" "c_null_ptr" "c_ptr" "c_short"
|
||||
"c_signed_char" "c_size_t" "c_vertical_tab" "call" "case" "ceiling"
|
||||
"char" "character" "character_storage_size" "class" "close" "cmplx"
|
||||
"command_argument_count" "common" "complex" "conjg" "contains" "continue"
|
||||
"copy_prefix" "copy_scatter" "copy_suffix" "cos" "cosh" "count"
|
||||
"count_prefix" "count_scatter" "count_suffix" "cpu_time" "cshift"
|
||||
"cycle" "cyclic" "data" "date_and_time" "dble" "deallocate" "deferred"
|
||||
"digits" "dim" "dimension" "distribute" "do" "dot_product" "double"
|
||||
"dprod" "dynamic" "elemental" "else" "elseif" "elsewhere" "end" "enddo"
|
||||
"endfile" "endif" "entry" "enum" "enumerator" "eoshift" "epsilon" "eq"
|
||||
"equivalence" "eqv" "error_unit" "exit" "exp" "exponent" "extends"
|
||||
"extends_type_of" "external" "extrinsic" "false" "file_storage_size"
|
||||
"final" "floor" "flush" "forall" "format" "fraction" "function" "ge"
|
||||
"generic" "get_command" "get_command_argument" "get_environment_variable"
|
||||
"goto" "grade_down" "grade_up" "gt" "hpf_alignment" "hpf_distribution"
|
||||
"hpf_template" "huge" "iachar" "iall" "iall_prefix" "iall_scatter"
|
||||
"iall_suffix" "iand" "iany" "iany_prefix" "iany_scatter" "iany_suffix"
|
||||
"ibclr" "ibits" "ibset" "ichar" "ieee_arithmetic" "ieee_exceptions"
|
||||
"ieee_features" "ieee_get_underflow_mode" "ieee_set_underflow_mode"
|
||||
"ieee_support_underflow_control" "ieor" "if" "ilen" "implicit"
|
||||
"import" "include" "independent" "index" "inherit" "input_unit"
|
||||
"inquire" "int" "integer" "intent" "interface" "intrinsic" "ior"
|
||||
"iostat_end" "iostat_eor" "iparity" "iparity_prefix" "iparity_scatter"
|
||||
"iparity_suffix" "ishft" "ishftc" "iso_c_binding" "iso_fortran_env"
|
||||
"kind" "lbound" "le" "leadz" "len" "len_trim" "lge" "lgt" "lle" "llt"
|
||||
"log" "log10" "logical" "lt" "matmul" "max" "maxexponent" "maxloc"
|
||||
"maxval" "maxval_prefix" "maxval_scatter" "maxval_suffix" "merge"
|
||||
"min" "minexponent" "minloc" "minval" "minval_prefix" "minval_scatter"
|
||||
"minval_suffix" "mod" "module" "modulo" "move_alloc" "mvbits" "namelist"
|
||||
"ne" "nearest" "neqv" "new" "new_line" "nint" "non_intrinsic"
|
||||
"non_overridable" "none" "nopass" "not" "null" "nullify"
|
||||
"number_of_processors" "numeric_storage_size" "only" "onto" "open"
|
||||
"operator" "optional" "or" "output_unit" "pack" "parameter" "parity"
|
||||
"parity_prefix" "parity_scatter" "parity_suffix" "pass" "pause"
|
||||
"pointer" "popcnt" "poppar" "precision" "present" "print" "private"
|
||||
"procedure" "processors" "processors_shape" "product" "product_prefix"
|
||||
"product_scatter" "product_suffix" "program" "protected" "public"
|
||||
"pure" "radix" "random_number" "random_seed" "range" "read" "real"
|
||||
"realign" "recursive" "redistribute" "repeat" "reshape" "result"
|
||||
"return" "rewind" "rrspacing" "same_type_as" "save" "scale" "scan"
|
||||
"select" "selected_char_kind" "selected_int_kind" "selected_real_kind"
|
||||
"sequence" "set_exponent" "shape" "sign" "sin" "sinh" "size" "spacing"
|
||||
"spread" "sqrt" "stop" "subroutine" "sum" "sum_prefix" "sum_scatter"
|
||||
"sum_suffix" "system_clock" "tan" "tanh" "target" "template" "then"
|
||||
"tiny" "transfer" "transpose" "trim" "true" "type" "ubound" "unpack"
|
||||
"use" "value" "verify" "volatile" "wait" "where" "while" "with" "write"))
|
||||
(go-mode
|
||||
;; From https://golang.org/ref/spec#Keywords
|
||||
;; Plus some basic types, for better programming experience.
|
||||
"bool" "break" "case" "chan" "complex128" "complex64" "const" "continue"
|
||||
"default" "defer" "else" "fallthrough" "float32" "float64"
|
||||
"for" "func" "go" "goto" "if" "import" "int" "int16" "int32"
|
||||
"int64" "int8" "interface" "map" "package" "range"
|
||||
"return" "select" "string" "struct" "switch" "type"
|
||||
"uint" "uint16" "uint32" "uint64" "uint8" "uintptr" "var")
|
||||
(java-mode
|
||||
"abstract" "assert" "boolean" "break" "byte" "case" "catch" "char" "class"
|
||||
"continue" "default" "do" "double" "else" "enum" "extends" "final"
|
||||
"finally" "float" "for" "if" "implements" "import" "instanceof" "int"
|
||||
"interface" "long" "native" "new" "package" "private" "protected" "public"
|
||||
"return" "short" "static" "strictfp" "super" "switch" "synchronized"
|
||||
"this" "throw" "throws" "transient" "try" "void" "volatile" "while")
|
||||
(javascript-mode
|
||||
;; https://tc39.github.io/ecma262/ + async, static and undefined
|
||||
"async" "await" "break" "case" "catch" "class" "const" "continue"
|
||||
"debugger" "default" "delete" "do" "else" "enum" "export" "extends" "false"
|
||||
"finally" "for" "function" "if" "import" "in" "instanceof" "let" "new"
|
||||
"null" "return" "static" "super" "switch" "this" "throw" "true" "try"
|
||||
"typeof" "undefined" "var" "void" "while" "with" "yield")
|
||||
(kotlin-mode
|
||||
"abstract" "annotation" "as" "break" "by" "catch" "class" "companion"
|
||||
"const" "constructor" "continue" "data" "do" "else" "enum" "false" "final"
|
||||
"finally" "for" "fun" "if" "import" "in" "init" "inner" "interface"
|
||||
"internal" "is" "lateinit" "nested" "null" "object" "open" "out" "override"
|
||||
"package" "private" "protected" "public" "return" "super" "this" "throw"
|
||||
"trait" "true" "try" "typealias" "val" "var" "when" "while")
|
||||
(objc-mode
|
||||
"@catch" "@class" "@encode" "@end" "@finally" "@implementation"
|
||||
"@interface" "@private" "@protected" "@protocol" "@public"
|
||||
"@selector" "@synchronized" "@throw" "@try" "alloc" "autorelease"
|
||||
"bycopy" "byref" "in" "inout" "oneway" "out" "release" "retain")
|
||||
(perl-mode
|
||||
;; from cperl.el
|
||||
"AUTOLOAD" "BEGIN" "CHECK" "CORE" "DESTROY" "END" "INIT" "__END__"
|
||||
"__FILE__" "__LINE__" "abs" "accept" "alarm" "and" "atan2" "bind"
|
||||
"binmode" "bless" "caller" "chdir" "chmod" "chomp" "chop" "chown" "chr"
|
||||
"chroot" "close" "closedir" "cmp" "connect" "continue" "cos"
|
||||
"crypt" "dbmclose" "dbmopen" "defined" "delete" "die" "do" "dump" "each"
|
||||
"else" "elsif" "endgrent" "endhostent" "endnetent" "endprotoent"
|
||||
"endpwent" "endservent" "eof" "eq" "eval" "exec" "exists" "exit" "exp"
|
||||
"fcntl" "fileno" "flock" "for" "foreach" "fork" "format" "formline"
|
||||
"ge" "getc" "getgrent" "getgrgid" "getgrnam" "gethostbyaddr"
|
||||
"gethostbyname" "gethostent" "getlogin" "getnetbyaddr" "getnetbyname"
|
||||
"getnetent" "getpeername" "getpgrp" "getppid" "getpriority"
|
||||
"getprotobyname" "getprotobynumber" "getprotoent" "getpwent" "getpwnam"
|
||||
"getpwuid" "getservbyname" "getservbyport" "getservent" "getsockname"
|
||||
"getsockopt" "glob" "gmtime" "goto" "grep" "gt" "hex" "if" "index" "int"
|
||||
"ioctl" "join" "keys" "kill" "last" "lc" "lcfirst" "le" "length"
|
||||
"link" "listen" "local" "localtime" "lock" "log" "lstat" "lt" "map"
|
||||
"mkdir" "msgctl" "msgget" "msgrcv" "msgsnd" "my" "ne" "next" "no"
|
||||
"not" "oct" "open" "opendir" "or" "ord" "our" "pack" "package" "pipe"
|
||||
"pop" "pos" "print" "printf" "push" "q" "qq" "quotemeta" "qw" "qx"
|
||||
"rand" "read" "readdir" "readline" "readlink" "readpipe" "recv" "redo"
|
||||
"ref" "rename" "require" "reset" "return" "reverse" "rewinddir" "rindex"
|
||||
"rmdir" "scalar" "seek" "seekdir" "select" "semctl" "semget" "semop"
|
||||
"send" "setgrent" "sethostent" "setnetent" "setpgrp" "setpriority"
|
||||
"setprotoent" "setpwent" "setservent" "setsockopt" "shift" "shmctl"
|
||||
"shmget" "shmread" "shmwrite" "shutdown" "sin" "sleep" "socket"
|
||||
"socketpair" "sort" "splice" "split" "sprintf" "sqrt" "srand" "stat"
|
||||
"study" "sub" "substr" "symlink" "syscall" "sysopen" "sysread" "system"
|
||||
"syswrite" "tell" "telldir" "tie" "time" "times" "tr" "truncate" "uc"
|
||||
"ucfirst" "umask" "undef" "unless" "unlink" "unpack" "unshift" "untie"
|
||||
"until" "use" "utime" "values" "vec" "wait" "waitpid"
|
||||
"wantarray" "warn" "while" "write" "x" "xor" "y")
|
||||
(php-mode
|
||||
"__CLASS__" "__DIR__" "__FILE__" "__FUNCTION__" "__LINE__" "__METHOD__"
|
||||
"__NAMESPACE__" "_once" "abstract" "and" "array" "as" "break" "case"
|
||||
"catch" "cfunction" "class" "clone" "const" "continue" "declare"
|
||||
"default" "die" "do" "echo" "else" "elseif" "empty" "enddeclare"
|
||||
"endfor" "endforeach" "endif" "endswitch" "endwhile" "eval" "exception"
|
||||
"exit" "extends" "final" "for" "foreach" "function" "global"
|
||||
"goto" "if" "implements" "include" "instanceof" "interface"
|
||||
"isset" "list" "namespace" "new" "old_function" "or" "php_user_filter"
|
||||
"print" "private" "protected" "public" "require" "require_once" "return"
|
||||
"static" "switch" "this" "throw" "try" "unset" "use" "var" "while" "xor")
|
||||
(python-mode
|
||||
;; https://docs.python.org/3/reference/lexical_analysis.html#keywords
|
||||
"False" "None" "True" "and" "as" "assert" "break" "class" "continue" "def"
|
||||
"del" "elif" "else" "except" "exec" "finally" "for" "from" "global" "if"
|
||||
"import" "in" "is" "lambda" "nonlocal" "not" "or" "pass" "print" "raise"
|
||||
"return" "try" "while" "with" "yield")
|
||||
(ruby-mode
|
||||
"BEGIN" "END" "alias" "and" "begin" "break" "case" "class" "def" "defined?"
|
||||
"do" "else" "elsif" "end" "ensure" "false" "for" "if" "in" "module"
|
||||
"next" "nil" "not" "or" "redo" "rescue" "retry" "return" "self" "super"
|
||||
"then" "true" "undef" "unless" "until" "when" "while" "yield")
|
||||
;; From https://doc.rust-lang.org/grammar.html#keywords
|
||||
;; but excluding unused reserved words: https://www.reddit.com/r/rust/comments/34fq0k/is_there_a_good_list_of_rusts_keywords/cqucvnj
|
||||
(rust-mode
|
||||
"Self"
|
||||
"as" "box" "break" "const" "continue" "crate" "else" "enum" "extern"
|
||||
"false" "fn" "for" "if" "impl" "in" "let" "loop" "macro" "match" "mod"
|
||||
"move" "mut" "pub" "ref" "return" "self" "static" "struct" "super"
|
||||
"trait" "true" "type" "unsafe" "use" "where" "while")
|
||||
(scala-mode
|
||||
"abstract" "case" "catch" "class" "def" "do" "else" "extends" "false"
|
||||
"final" "finally" "for" "forSome" "if" "implicit" "import" "lazy" "match"
|
||||
"new" "null" "object" "override" "package" "private" "protected"
|
||||
"return" "sealed" "super" "this" "throw" "trait" "true" "try" "type" "val"
|
||||
"var" "while" "with" "yield")
|
||||
(swift-mode
|
||||
"Protocol" "Self" "Type" "and" "as" "assignment" "associatedtype"
|
||||
"associativity" "available" "break" "case" "catch" "class" "column" "continue"
|
||||
"convenience" "default" "defer" "deinit" "didSet" "do" "dynamic" "dynamicType"
|
||||
"else" "elseif" "endif" "enum" "extension" "fallthrough" "false" "file"
|
||||
"fileprivate" "final" "for" "func" "function" "get" "guard" "higherThan" "if"
|
||||
"import" "in" "indirect" "infix" "init" "inout" "internal" "is" "lazy" "left"
|
||||
"let" "line" "lowerThan" "mutating" "nil" "none" "nonmutating" "open"
|
||||
"operator" "optional" "override" "postfix" "precedence" "precedencegroup"
|
||||
"prefix" "private" "protocol" "public" "repeat" "required" "rethrows" "return"
|
||||
"right" "selector" "self" "set" "static" "struct" "subscript" "super" "switch"
|
||||
"throw" "throws" "true" "try" "typealias" "unowned" "var" "weak" "where"
|
||||
"while" "willSet")
|
||||
(julia-mode
|
||||
"abstract" "break" "case" "catch" "const" "continue" "do" "else" "elseif"
|
||||
"end" "eval" "export" "false" "finally" "for" "function" "global" "if"
|
||||
"ifelse" "immutable" "import" "importall" "in" "let" "macro" "module"
|
||||
"otherwise" "quote" "return" "switch" "throw" "true" "try" "type"
|
||||
"typealias" "using" "while"
|
||||
)
|
||||
;; From https://github.com/apache/thrift/blob/master/contrib/thrift.el
|
||||
(thrift-mode
|
||||
"binary" "bool" "byte" "const" "double" "enum" "exception" "extends"
|
||||
"i16" "i32" "i64" "include" "list" "map" "oneway" "optional" "required"
|
||||
"service" "set" "string" "struct" "throws" "typedef" "void"
|
||||
)
|
||||
;; aliases
|
||||
(js2-mode . javascript-mode)
|
||||
(js2-jsx-mode . javascript-mode)
|
||||
(espresso-mode . javascript-mode)
|
||||
(js-mode . javascript-mode)
|
||||
(js-jsx-mode . javascript-mode)
|
||||
(rjsx-mode . javascript-mode)
|
||||
(cperl-mode . perl-mode)
|
||||
(jde-mode . java-mode)
|
||||
(ess-julia-mode . julia-mode)
|
||||
(enh-ruby-mode . ruby-mode))
|
||||
"Alist mapping major-modes to sorted keywords for `company-keywords'.")
|
||||
|
||||
;;;###autoload
|
||||
(defun company-keywords (command &optional arg &rest ignored)
|
||||
"`company-mode' backend for programming language keywords."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-keywords))
|
||||
(prefix (and (assq major-mode company-keywords-alist)
|
||||
(not (company-in-string-or-comment))
|
||||
(or (company-grab-symbol) 'stop)))
|
||||
(candidates
|
||||
(let ((completion-ignore-case nil)
|
||||
(symbols (cdr (assq major-mode company-keywords-alist))))
|
||||
(all-completions arg (if (consp symbols)
|
||||
symbols
|
||||
(cdr (assq symbols company-keywords-alist))))))
|
||||
(sorted t)))
|
||||
|
||||
(provide 'company-keywords)
|
||||
;;; company-keywords.el ends here
|
Binary file not shown.
|
@ -0,0 +1,143 @@
|
|||
;;; company-nxml.el --- company-mode completion backend for nxml-mode
|
||||
|
||||
;; Copyright (C) 2009-2011, 2013, 2018 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; In Emacs >= 26, company-capf is used instead.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defvar rng-open-elements)
|
||||
(defvar rng-validate-mode)
|
||||
(defvar rng-in-attribute-regex)
|
||||
(defvar rng-in-attribute-value-regex)
|
||||
(declare-function rng-set-state-after "rng-nxml")
|
||||
(declare-function rng-match-possible-start-tag-names "rng-match")
|
||||
(declare-function rng-adjust-state-for-attribute "rng-nxml")
|
||||
(declare-function rng-match-possible-attribute-names "rng-match")
|
||||
(declare-function rng-adjust-state-for-attribute-value "rng-nxml")
|
||||
(declare-function rng-match-possible-value-strings "rng-match")
|
||||
|
||||
(defconst company-nxml-token-regexp
|
||||
"\\(?:[_[:alpha:]][-._[:alnum:]]*\\_>\\)")
|
||||
|
||||
(defvar company-nxml-in-attribute-value-regexp
|
||||
(replace-regexp-in-string "w" company-nxml-token-regexp
|
||||
"<w\\(?::w\\)?\
|
||||
\\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
|
||||
\[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
|
||||
\[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
|
||||
\\(\"\\([^\"]*\\>\\)\\|'\\([^']*\\>\\)\\)\\="
|
||||
t t))
|
||||
|
||||
(defvar company-nxml-in-tag-name-regexp
|
||||
(replace-regexp-in-string "w" company-nxml-token-regexp
|
||||
"<\\(/?w\\(?::w?\\)?\\)?\\=" t t))
|
||||
|
||||
(defun company-nxml-all-completions (prefix alist)
|
||||
(let ((candidates (mapcar 'cdr alist))
|
||||
(case-fold-search nil)
|
||||
filtered)
|
||||
(when (cdar rng-open-elements)
|
||||
(push (concat "/" (cdar rng-open-elements)) candidates))
|
||||
(setq candidates (sort (all-completions prefix candidates) 'string<))
|
||||
(while candidates
|
||||
(unless (equal (car candidates) (car filtered))
|
||||
(push (car candidates) filtered))
|
||||
(pop candidates))
|
||||
(nreverse filtered)))
|
||||
|
||||
(defmacro company-nxml-prepared (&rest body)
|
||||
(declare (indent 0) (debug t))
|
||||
`(let ((lt-pos (save-excursion (search-backward "<" nil t)))
|
||||
xmltok-dtd)
|
||||
(when (and lt-pos (= (rng-set-state-after lt-pos) lt-pos))
|
||||
,@body)))
|
||||
|
||||
(defun company-nxml-tag (command &optional arg &rest ignored)
|
||||
(cl-case command
|
||||
(prefix (and (derived-mode-p 'nxml-mode)
|
||||
rng-validate-mode
|
||||
(company-grab company-nxml-in-tag-name-regexp 1)))
|
||||
(candidates (company-nxml-prepared
|
||||
(company-nxml-all-completions
|
||||
arg (rng-match-possible-start-tag-names))))
|
||||
(sorted t)))
|
||||
|
||||
(defun company-nxml-attribute (command &optional arg &rest ignored)
|
||||
(cl-case command
|
||||
(prefix (and (derived-mode-p 'nxml-mode)
|
||||
rng-validate-mode
|
||||
(memq (char-after) '(?\ ?\t ?\n)) ;; outside word
|
||||
(company-grab rng-in-attribute-regex 1)))
|
||||
(candidates (company-nxml-prepared
|
||||
(and (rng-adjust-state-for-attribute
|
||||
lt-pos (- (point) (length arg)))
|
||||
(company-nxml-all-completions
|
||||
arg (rng-match-possible-attribute-names)))))
|
||||
(sorted t)))
|
||||
|
||||
(defun company-nxml-attribute-value (command &optional arg &rest ignored)
|
||||
(cl-case command
|
||||
(prefix (and (derived-mode-p 'nxml-mode)
|
||||
rng-validate-mode
|
||||
(and (memq (char-after) '(?' ?\" ?\ ?\t ?\n)) ;; outside word
|
||||
(looking-back company-nxml-in-attribute-value-regexp nil)
|
||||
(or (match-string-no-properties 4)
|
||||
(match-string-no-properties 5)
|
||||
""))))
|
||||
(candidates (company-nxml-prepared
|
||||
(let (attr-start attr-end colon)
|
||||
(and (looking-back rng-in-attribute-value-regex lt-pos)
|
||||
(setq colon (match-beginning 2)
|
||||
attr-start (match-beginning 1)
|
||||
attr-end (match-end 1))
|
||||
(rng-adjust-state-for-attribute lt-pos attr-start)
|
||||
(rng-adjust-state-for-attribute-value
|
||||
attr-start colon attr-end)
|
||||
(all-completions
|
||||
arg (rng-match-possible-value-strings))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-nxml (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for `nxml-mode'."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-nxml))
|
||||
(prefix (or (company-nxml-tag 'prefix)
|
||||
(company-nxml-attribute 'prefix)
|
||||
(company-nxml-attribute-value 'prefix)))
|
||||
(candidates (cond
|
||||
((company-nxml-tag 'prefix)
|
||||
(company-nxml-tag 'candidates arg))
|
||||
((company-nxml-attribute 'prefix)
|
||||
(company-nxml-attribute 'candidates arg))
|
||||
((company-nxml-attribute-value 'prefix)
|
||||
(sort (company-nxml-attribute-value 'candidates arg)
|
||||
'string<))))
|
||||
(sorted t)))
|
||||
|
||||
(provide 'company-nxml)
|
||||
;;; company-nxml.el ends here
|
Binary file not shown.
|
@ -0,0 +1,57 @@
|
|||
;;; company-oddmuse.el --- company-mode completion backend for oddmuse-mode
|
||||
|
||||
;; Copyright (C) 2009-2011, 2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
(eval-when-compile (require 'yaoddmuse nil t))
|
||||
(eval-when-compile (require 'oddmuse nil t))
|
||||
|
||||
(defvar company-oddmuse-link-regexp
|
||||
"\\(\\<[A-Z][[:alnum:]]*\\>\\)\\|\\[\\[\\([[:alnum:]]+\\>\\|\\)")
|
||||
|
||||
(defun company-oddmuse-get-page-table ()
|
||||
(cl-case major-mode
|
||||
(yaoddmuse-mode (with-no-warnings
|
||||
(yaoddmuse-get-pagename-table yaoddmuse-wikiname)))
|
||||
(oddmuse-mode (with-no-warnings
|
||||
(oddmuse-make-completion-table oddmuse-wiki)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-oddmuse (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for `oddmuse-mode'."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-oddmuse))
|
||||
(prefix (let ((case-fold-search nil))
|
||||
(and (memq major-mode '(oddmuse-mode yaoddmuse-mode))
|
||||
(looking-back company-oddmuse-link-regexp (point-at-bol))
|
||||
(or (match-string 1)
|
||||
(match-string 2)))))
|
||||
(candidates (all-completions arg (company-oddmuse-get-page-table)))))
|
||||
|
||||
(provide 'company-oddmuse)
|
||||
;;; company-oddmuse.el ends here
|
Binary file not shown.
|
@ -0,0 +1,12 @@
|
|||
(define-package "company" "20180802.1207" "Modular text completion framework"
|
||||
'((emacs "24.3"))
|
||||
:keywords
|
||||
'("abbrev" "convenience" "matching")
|
||||
:authors
|
||||
'(("Nikolaj Schumacher"))
|
||||
:maintainer
|
||||
'("Dmitry Gutov" . "dgutov@yandex.ru")
|
||||
:url "http://company-mode.github.io/")
|
||||
;; Local Variables:
|
||||
;; no-byte-compile: t
|
||||
;; End:
|
|
@ -0,0 +1,168 @@
|
|||
;;; company-semantic.el --- company-mode completion backend using Semantic
|
||||
|
||||
;; Copyright (C) 2009-2011, 2013-2016 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'company-template)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defvar semantic-idle-summary-function)
|
||||
(declare-function semantic-documentation-for-tag "semantic/doc" )
|
||||
(declare-function semantic-analyze-current-context "semantic/analyze")
|
||||
(declare-function semantic-analyze-possible-completions "semantic/complete")
|
||||
(declare-function semantic-analyze-find-tags-by-prefix "semantic/analyze/fcn")
|
||||
(declare-function semantic-tag-class "semantic/tag")
|
||||
(declare-function semantic-tag-name "semantic/tag")
|
||||
(declare-function semantic-tag-start "semantic/tag")
|
||||
(declare-function semantic-tag-buffer "semantic/tag")
|
||||
(declare-function semantic-active-p "semantic")
|
||||
(declare-function semantic-format-tag-prototype "semantic/format")
|
||||
|
||||
(defgroup company-semantic nil
|
||||
"Completion backend using Semantic."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
|
||||
"The function turning a semantic tag into doc information."
|
||||
:type 'function)
|
||||
|
||||
(defcustom company-semantic-begin-after-member-access t
|
||||
"When non-nil, automatic completion will start whenever the current
|
||||
symbol is preceded by \".\", \"->\" or \"::\", ignoring
|
||||
`company-minimum-prefix-length'.
|
||||
|
||||
If `company-begin-commands' is a list, it should include `c-electric-lt-gt'
|
||||
and `c-electric-colon', for automatic completion right after \">\" and
|
||||
\":\"."
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom company-semantic-insert-arguments t
|
||||
"When non-nil, insert function arguments as a template after completion."
|
||||
:type 'boolean
|
||||
:package-version '(company . "0.9.0"))
|
||||
|
||||
(defvar company-semantic-modes '(c-mode c++-mode jde-mode java-mode))
|
||||
|
||||
(defvar-local company-semantic--current-tags nil
|
||||
"Tags for the current context.")
|
||||
|
||||
(defun company-semantic-documentation-for-tag (tag)
|
||||
(when (semantic-tag-buffer tag)
|
||||
;; When TAG's buffer is unknown, the function below raises an error.
|
||||
(semantic-documentation-for-tag tag)))
|
||||
|
||||
(defun company-semantic-doc-or-summary (tag)
|
||||
(or (company-semantic-documentation-for-tag tag)
|
||||
(and (require 'semantic-idle nil t)
|
||||
(require 'semantic/idle nil t)
|
||||
(funcall semantic-idle-summary-function tag nil t))))
|
||||
|
||||
(defun company-semantic-summary-and-doc (tag)
|
||||
(let ((doc (company-semantic-documentation-for-tag tag))
|
||||
(summary (funcall semantic-idle-summary-function tag nil t)))
|
||||
(and (stringp doc)
|
||||
(string-match "\n*\\(.*\\)$" doc)
|
||||
(setq doc (match-string 1 doc)))
|
||||
(concat summary
|
||||
(when doc
|
||||
(if (< (+ (length doc) (length summary) 4) (window-width))
|
||||
" -- "
|
||||
"\n"))
|
||||
doc)))
|
||||
|
||||
(defun company-semantic-doc-buffer (tag)
|
||||
(let ((doc (company-semantic-documentation-for-tag tag)))
|
||||
(when doc
|
||||
(company-doc-buffer
|
||||
(concat (funcall semantic-idle-summary-function tag nil t)
|
||||
"\n"
|
||||
doc)))))
|
||||
|
||||
(defsubst company-semantic-completions (prefix)
|
||||
(ignore-errors
|
||||
(let ((completion-ignore-case nil)
|
||||
(context (semantic-analyze-current-context)))
|
||||
(setq company-semantic--current-tags
|
||||
(semantic-analyze-possible-completions context 'no-unique))
|
||||
(all-completions prefix company-semantic--current-tags))))
|
||||
|
||||
(defun company-semantic-completions-raw (prefix)
|
||||
(setq company-semantic--current-tags nil)
|
||||
(dolist (tag (semantic-analyze-find-tags-by-prefix prefix))
|
||||
(unless (eq (semantic-tag-class tag) 'include)
|
||||
(push tag company-semantic--current-tags)))
|
||||
(delete "" (mapcar 'semantic-tag-name company-semantic--current-tags)))
|
||||
|
||||
(defun company-semantic-annotation (argument tags)
|
||||
(let* ((tag (assq argument tags))
|
||||
(kind (when tag (elt tag 1))))
|
||||
(cl-case kind
|
||||
(function (let* ((prototype (semantic-format-tag-prototype tag nil nil))
|
||||
(par-pos (string-match "(" prototype)))
|
||||
(when par-pos (substring prototype par-pos)))))))
|
||||
|
||||
(defun company-semantic--prefix ()
|
||||
(if company-semantic-begin-after-member-access
|
||||
(company-grab-symbol-cons "\\.\\|->\\|::" 2)
|
||||
(company-grab-symbol)))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-semantic (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend using CEDET Semantic."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-semantic))
|
||||
(prefix (and (featurep 'semantic)
|
||||
(semantic-active-p)
|
||||
(memq major-mode company-semantic-modes)
|
||||
(not (company-in-string-or-comment))
|
||||
(or (company-semantic--prefix) 'stop)))
|
||||
(candidates (if (and (equal arg "")
|
||||
(not (looking-back "->\\|\\.\\|::" (- (point) 2))))
|
||||
(company-semantic-completions-raw arg)
|
||||
(company-semantic-completions arg)))
|
||||
(meta (funcall company-semantic-metadata-function
|
||||
(assoc arg company-semantic--current-tags)))
|
||||
(annotation (company-semantic-annotation arg
|
||||
company-semantic--current-tags))
|
||||
(doc-buffer (company-semantic-doc-buffer
|
||||
(assoc arg company-semantic--current-tags)))
|
||||
;; Because "" is an empty context and doesn't return local variables.
|
||||
(no-cache (equal arg ""))
|
||||
(duplicates t)
|
||||
(location (let ((tag (assoc arg company-semantic--current-tags)))
|
||||
(when (buffer-live-p (semantic-tag-buffer tag))
|
||||
(cons (semantic-tag-buffer tag)
|
||||
(semantic-tag-start tag)))))
|
||||
(post-completion (let ((anno (company-semantic-annotation
|
||||
arg company-semantic--current-tags)))
|
||||
(when (and company-semantic-insert-arguments anno)
|
||||
(insert anno)
|
||||
(company-template-c-like-templatify (concat arg anno)))
|
||||
))))
|
||||
|
||||
(provide 'company-semantic)
|
||||
;;; company-semantic.el ends here
|
Binary file not shown.
|
@ -0,0 +1,260 @@
|
|||
;;; company-template.el --- utility library for template expansion
|
||||
|
||||
;; Copyright (C) 2009, 2010, 2014-2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
|
||||
(defface company-template-field
|
||||
'((((background dark)) (:background "yellow" :foreground "black"))
|
||||
(((background light)) (:background "orange" :foreground "black")))
|
||||
"Face used for editable text in template fields."
|
||||
:group 'company)
|
||||
|
||||
(defvar company-template-nav-map
|
||||
(let ((keymap (make-sparse-keymap)))
|
||||
(define-key keymap [tab] 'company-template-forward-field)
|
||||
(define-key keymap (kbd "TAB") 'company-template-forward-field)
|
||||
keymap))
|
||||
|
||||
(defvar company-template-field-map
|
||||
(let ((keymap (make-sparse-keymap)))
|
||||
(set-keymap-parent keymap company-template-nav-map)
|
||||
(define-key keymap (kbd "C-d") 'company-template-clear-field)
|
||||
keymap))
|
||||
|
||||
(defvar-local company-template--buffer-templates nil)
|
||||
|
||||
;; interactive ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defun company-template-templates-at (pos)
|
||||
(let (os)
|
||||
(dolist (o (overlays-at pos))
|
||||
;; FIXME: Always return the whole list of templates?
|
||||
;; We remove templates not at point after every command.
|
||||
(when (memq o company-template--buffer-templates)
|
||||
(push o os)))
|
||||
os))
|
||||
|
||||
(defun company-template-move-to-first (templ)
|
||||
(interactive)
|
||||
(goto-char (overlay-start templ))
|
||||
(company-template-forward-field))
|
||||
|
||||
(defun company-template-forward-field ()
|
||||
(interactive)
|
||||
(let ((start (point))
|
||||
(next-field-start (company-template-find-next-field)))
|
||||
(push-mark)
|
||||
(goto-char next-field-start)
|
||||
(company-template-remove-field (company-template-field-at start))))
|
||||
|
||||
(defun company-template-clear-field ()
|
||||
"Clear the field at point."
|
||||
(interactive)
|
||||
(let ((ovl (company-template-field-at (point))))
|
||||
(when ovl
|
||||
(company-template-remove-field ovl t)
|
||||
(let ((after-clear-fn
|
||||
(overlay-get ovl 'company-template-after-clear)))
|
||||
(when (functionp after-clear-fn)
|
||||
(funcall after-clear-fn))))))
|
||||
|
||||
(defun company-template--after-clear-c-like-field ()
|
||||
"Function that can be called after deleting a field of a c-like template.
|
||||
For c-like templates it is set as `after-post-fn' property on fields in
|
||||
`company-template-add-field'. If there is a next field, delete everything
|
||||
from point to it. If there is no field after point, remove preceding comma
|
||||
if present."
|
||||
(let* ((pos (point))
|
||||
(next-field-start (company-template-find-next-field))
|
||||
(last-field-p (not (company-template-field-at next-field-start))))
|
||||
(cond ((and (not last-field-p)
|
||||
(< pos next-field-start)
|
||||
(string-match "^[ ]*,+[ ]*$" (buffer-substring-no-properties
|
||||
pos next-field-start)))
|
||||
(delete-region pos next-field-start))
|
||||
((and last-field-p
|
||||
(looking-back ",+[ ]*" (line-beginning-position)))
|
||||
(delete-region (match-beginning 0) pos)))))
|
||||
|
||||
(defun company-template-find-next-field ()
|
||||
(let* ((start (point))
|
||||
(templates (company-template-templates-at start))
|
||||
(minimum (apply 'max (mapcar 'overlay-end templates)))
|
||||
(fields (cl-loop for templ in templates
|
||||
append (overlay-get templ 'company-template-fields))))
|
||||
(dolist (pos (mapcar 'overlay-start fields) minimum)
|
||||
(and pos
|
||||
(> pos start)
|
||||
(< pos minimum)
|
||||
(setq minimum pos)))))
|
||||
|
||||
(defun company-template-field-at (&optional point)
|
||||
(cl-loop for ovl in (overlays-at (or point (point)))
|
||||
when (overlay-get ovl 'company-template-parent)
|
||||
return ovl))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defun company-template-declare-template (beg end)
|
||||
(let ((ov (make-overlay beg end)))
|
||||
;; (overlay-put ov 'face 'highlight)
|
||||
(overlay-put ov 'keymap company-template-nav-map)
|
||||
(overlay-put ov 'priority 101)
|
||||
(overlay-put ov 'evaporate t)
|
||||
(push ov company-template--buffer-templates)
|
||||
(add-hook 'post-command-hook 'company-template-post-command nil t)
|
||||
ov))
|
||||
|
||||
(defun company-template-remove-template (templ)
|
||||
(mapc 'company-template-remove-field
|
||||
(overlay-get templ 'company-template-fields))
|
||||
(setq company-template--buffer-templates
|
||||
(delq templ company-template--buffer-templates))
|
||||
(delete-overlay templ))
|
||||
|
||||
(defun company-template-add-field (templ beg end &optional display after-clear-fn)
|
||||
"Add new field to template TEMPL spanning from BEG to END.
|
||||
When DISPLAY is non-nil, set the respective property on the overlay.
|
||||
Leave point at the end of the field.
|
||||
AFTER-CLEAR-FN is a function that can be used to apply custom behavior
|
||||
after deleting a field in `company-template-remove-field'."
|
||||
(cl-assert templ)
|
||||
(when (> end (overlay-end templ))
|
||||
(move-overlay templ (overlay-start templ) end))
|
||||
(let ((ov (make-overlay beg end))
|
||||
(siblings (overlay-get templ 'company-template-fields)))
|
||||
;; (overlay-put ov 'evaporate t)
|
||||
(overlay-put ov 'intangible t)
|
||||
(overlay-put ov 'face 'company-template-field)
|
||||
(when display
|
||||
(overlay-put ov 'display display))
|
||||
(overlay-put ov 'company-template-parent templ)
|
||||
(overlay-put ov 'insert-in-front-hooks '(company-template-insert-hook))
|
||||
(when after-clear-fn
|
||||
(overlay-put ov 'company-template-after-clear after-clear-fn))
|
||||
(overlay-put ov 'keymap company-template-field-map)
|
||||
(overlay-put ov 'priority 101)
|
||||
(push ov siblings)
|
||||
(overlay-put templ 'company-template-fields siblings)))
|
||||
|
||||
(defun company-template-remove-field (ovl &optional clear)
|
||||
(when (overlayp ovl)
|
||||
(when (overlay-buffer ovl)
|
||||
(when clear
|
||||
(delete-region (overlay-start ovl) (overlay-end ovl)))
|
||||
(delete-overlay ovl))
|
||||
(let* ((templ (overlay-get ovl 'company-template-parent))
|
||||
(siblings (overlay-get templ 'company-template-fields)))
|
||||
(setq siblings (delq ovl siblings))
|
||||
(overlay-put templ 'company-template-fields siblings))))
|
||||
|
||||
(defun company-template-clean-up (&optional pos)
|
||||
"Clean up all templates that don't contain POS."
|
||||
(let ((local-ovs (overlays-at (or pos (point)))))
|
||||
(dolist (templ company-template--buffer-templates)
|
||||
(unless (memq templ local-ovs)
|
||||
(company-template-remove-template templ)))))
|
||||
|
||||
;; hooks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defun company-template-insert-hook (ovl after-p &rest _ignore)
|
||||
"Called when a snippet input prompt is modified."
|
||||
(unless after-p
|
||||
(company-template-remove-field ovl t)))
|
||||
|
||||
(defun company-template-post-command ()
|
||||
(company-template-clean-up)
|
||||
(unless company-template--buffer-templates
|
||||
(remove-hook 'post-command-hook 'company-template-post-command t)))
|
||||
|
||||
;; common ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defun company-template-c-like-templatify (call)
|
||||
(let* ((end (point-marker))
|
||||
(beg (- (point) (length call)))
|
||||
(templ (company-template-declare-template beg end))
|
||||
paren-open paren-close)
|
||||
(with-syntax-table (make-syntax-table (syntax-table))
|
||||
(modify-syntax-entry ?< "(")
|
||||
(modify-syntax-entry ?> ")")
|
||||
(when (search-backward ")" beg t)
|
||||
(setq paren-close (point-marker))
|
||||
(forward-char 1)
|
||||
(delete-region (point) end)
|
||||
(backward-sexp)
|
||||
(forward-char 1)
|
||||
(setq paren-open (point-marker)))
|
||||
(when (search-backward ">" beg t)
|
||||
(let ((angle-close (point-marker)))
|
||||
(forward-char 1)
|
||||
(backward-sexp)
|
||||
(forward-char)
|
||||
(company-template--c-like-args templ angle-close)))
|
||||
(when (looking-back "\\((\\*)\\)(" (line-beginning-position))
|
||||
(delete-region (match-beginning 1) (match-end 1)))
|
||||
(when paren-open
|
||||
(goto-char paren-open)
|
||||
(company-template--c-like-args templ paren-close)))
|
||||
(if (overlay-get templ 'company-template-fields)
|
||||
(company-template-move-to-first templ)
|
||||
(company-template-remove-template templ)
|
||||
(goto-char end))))
|
||||
|
||||
(defun company-template--c-like-args (templ end)
|
||||
(let ((last-pos (point)))
|
||||
(while (re-search-forward "\\([^,]+\\),?" end 'move)
|
||||
(when (zerop (car (parse-partial-sexp last-pos (point))))
|
||||
(company-template-add-field templ last-pos (match-end 1) nil
|
||||
#'company-template--after-clear-c-like-field)
|
||||
(skip-chars-forward " ")
|
||||
(setq last-pos (point))))))
|
||||
|
||||
;; objc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defun company-template-objc-templatify (selector)
|
||||
(let* ((end (point-marker))
|
||||
(beg (- (point) (length selector) 1))
|
||||
(templ (company-template-declare-template beg end))
|
||||
(cnt 0))
|
||||
(save-excursion
|
||||
(goto-char beg)
|
||||
(catch 'stop
|
||||
(while (search-forward ":" end t)
|
||||
(if (looking-at "\\(([^)]*)\\) ?")
|
||||
(company-template-add-field templ (point) (match-end 1))
|
||||
;; Not sure which conditions this case manifests under, but
|
||||
;; apparently it did before, when I wrote the first test for this
|
||||
;; function. FIXME: Revisit it.
|
||||
(company-template-add-field templ (point)
|
||||
(progn
|
||||
(insert (format "arg%d" cnt))
|
||||
(point)))
|
||||
(when (< (point) end)
|
||||
(insert " "))
|
||||
(cl-incf cnt))
|
||||
(when (>= (point) end)
|
||||
(throw 'stop t)))))
|
||||
(company-template-move-to-first templ)))
|
||||
|
||||
(provide 'company-template)
|
||||
;;; company-template.el ends here
|
Binary file not shown.
|
@ -0,0 +1,71 @@
|
|||
;;; company-tempo.el --- company-mode completion backend for tempo
|
||||
|
||||
;; Copyright (C) 2009-2011, 2015 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
(require 'tempo)
|
||||
|
||||
(defgroup company-tempo nil
|
||||
"Tempo completion backend."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-tempo-expand nil
|
||||
"Whether to expand a tempo tag after completion."
|
||||
:type '(choice (const :tag "Off" nil)
|
||||
(const :tag "On" t)))
|
||||
|
||||
(defsubst company-tempo-lookup (match)
|
||||
(cdr (assoc match (tempo-build-collection))))
|
||||
|
||||
(defun company-tempo-insert (match)
|
||||
"Replace MATCH with the expanded tempo template."
|
||||
(search-backward match)
|
||||
(goto-char (match-beginning 0))
|
||||
(replace-match "")
|
||||
(call-interactively (company-tempo-lookup match)))
|
||||
|
||||
(defsubst company-tempo-meta (match)
|
||||
(let ((templ (company-tempo-lookup match))
|
||||
doc)
|
||||
(and templ
|
||||
(setq doc (documentation templ t))
|
||||
(car (split-string doc "\n" t)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-tempo (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for tempo."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-tempo))
|
||||
(prefix (or (car (tempo-find-match-string tempo-match-finder)) ""))
|
||||
(candidates (all-completions arg (tempo-build-collection)))
|
||||
(meta (company-tempo-meta arg))
|
||||
(post-completion (when company-tempo-expand (company-tempo-insert arg)))
|
||||
(sorted t)))
|
||||
|
||||
(provide 'company-tempo)
|
||||
;;; company-tempo.el ends here
|
Binary file not shown.
|
@ -0,0 +1,174 @@
|
|||
;;; company-tng.el --- company-mode configuration for single-button interaction
|
||||
|
||||
;; Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikita Leshenko
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; company-tng (Tab and Go) allows you to perform completion using just TAB.
|
||||
;; Pressing it will both select the next completion candidate in the list and
|
||||
;; insert it into the buffer (or make it look like it's inserted, in fact).
|
||||
;;
|
||||
;; It cycles the candidates like `yank-pop' or `dabbrev-expand' or Vim:
|
||||
;; Pressing TAB selects the first item in the completion menu and inserts it in
|
||||
;; the buffer. Pressing TAB again selects the second item and replaces the
|
||||
;; "inserted" item with the second one. This can continue as long as the user
|
||||
;; wishes to cycle through the menu. You can also press S-TAB to select the
|
||||
;; previous candidate, of course.
|
||||
;;
|
||||
;; The benefits are that you only have to use one shortcut key and there is no
|
||||
;; need to confirm the entry.
|
||||
;;
|
||||
;; Usage:
|
||||
;;
|
||||
;; To apply the default configuration for company-tng call
|
||||
;; `company-tng-configure-default' from your init script.
|
||||
;;
|
||||
;; You can also configure company-tng manually:
|
||||
;;
|
||||
;; Add `company-tng-frontend' to `company-frontends':
|
||||
;;
|
||||
;; (add-to-list 'company-frontends 'company-tng-frontend)
|
||||
;;
|
||||
;; We recommend to bind TAB to `company-select-next', S-TAB to
|
||||
;; `company-select-previous', and unbind RET and other now-unnecessary
|
||||
;; keys from `company-active-map':
|
||||
;;
|
||||
;; (define-key company-active-map (kbd "TAB") 'company-select-next)
|
||||
;; (define-key company-active-map (kbd "<backtab>") 'company-select-previous)
|
||||
;; (define-key company-active-map (kbd "RET") nil)
|
||||
;;
|
||||
;; Note that it's not necessary to rebind keys to use this frontend,
|
||||
;; you can use the arrow keys or M-n/M-p to select and insert
|
||||
;; candidates. You also need to decide which keys to unbind, depending
|
||||
;; on whether you want them to do the Company action or the default
|
||||
;; Emacs action (for example C-s or C-w).
|
||||
;;
|
||||
;; We recommend to disable `company-require-match' to allow free typing at any
|
||||
;; point.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defvar-local company-tng--overlay nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun company-tng-frontend (command)
|
||||
"When the user changes the selection at least once, this
|
||||
frontend will display the candidate in the buffer as if it's
|
||||
already there and any key outside of `company-active-map' will
|
||||
confirm the selection and finish the completion."
|
||||
(cl-case command
|
||||
(show
|
||||
(let ((ov (make-overlay (point) (point))))
|
||||
(setq company-tng--overlay ov)
|
||||
(overlay-put ov 'priority 2))
|
||||
(advice-add 'company-select-next :before-until 'company-tng--allow-unselected)
|
||||
(advice-add 'company-fill-propertize :filter-args 'company-tng--adjust-tooltip-highlight))
|
||||
(update
|
||||
(let ((ov company-tng--overlay)
|
||||
(selected (nth company-selection company-candidates))
|
||||
(prefix (length company-prefix)))
|
||||
(move-overlay ov (- (point) prefix) (point))
|
||||
(overlay-put ov
|
||||
(if (= prefix 0) 'after-string 'display)
|
||||
(and company-selection-changed selected))))
|
||||
(hide
|
||||
(when company-tng--overlay
|
||||
(delete-overlay company-tng--overlay)
|
||||
(kill-local-variable 'company-tng--overlay))
|
||||
(advice-remove 'company-select-next 'company-tng--allow-unselected)
|
||||
(advice-remove 'company-fill-propertize 'company-tng--adjust-tooltip-highlight))
|
||||
(pre-command
|
||||
(when (and company-selection-changed
|
||||
(not (company--company-command-p (this-command-keys))))
|
||||
(company--unread-this-command-keys)
|
||||
(setq this-command 'company-complete-selection)
|
||||
(advice-add 'company-call-backend :before-until 'company-tng--supress-post-completion)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-tng-configure-default ()
|
||||
"Applies the default configuration to enable company-tng."
|
||||
(setq company-require-match nil)
|
||||
(setq company-frontends '(company-tng-frontend
|
||||
company-pseudo-tooltip-frontend
|
||||
company-echo-metadata-frontend))
|
||||
(let ((keymap company-active-map))
|
||||
(define-key keymap [return] nil)
|
||||
(define-key keymap (kbd "RET") nil)
|
||||
(define-key keymap [tab] 'company-select-next)
|
||||
(define-key keymap (kbd "TAB") 'company-select-next)
|
||||
(define-key keymap [backtab] 'company-select-previous)
|
||||
(define-key keymap (kbd "S-TAB") 'company-select-previous)))
|
||||
|
||||
(defun company-tng--allow-unselected (&optional arg)
|
||||
"Advice `company-select-next' to allow for an 'unselected'
|
||||
state. Unselected means that no user interaction took place on the
|
||||
completion candidates and it's marked by setting
|
||||
`company-selection-changed' to nil. This advice will call the underlying
|
||||
`company-select-next' unless we need to transition to or from an unselected
|
||||
state.
|
||||
|
||||
Possible state transitions:
|
||||
- (arg > 0) unselected -> first candidate selected
|
||||
- (arg < 0) first candidate selected -> unselected
|
||||
- (arg < 0 wrap-round) unselected -> last candidate selected
|
||||
- (arg < 0 no wrap-round) unselected -> unselected
|
||||
|
||||
There is no need to advice `company-select-previous' because it calls
|
||||
`company-select-next' internally."
|
||||
(cond
|
||||
;; Selecting next
|
||||
((or (not arg) (> arg 0))
|
||||
(unless company-selection-changed
|
||||
(company-set-selection (1- (or arg 1)) 'force-update)
|
||||
t))
|
||||
;; Selecting previous
|
||||
((< arg 0)
|
||||
(when (and company-selection-changed
|
||||
(< (+ company-selection arg) 0))
|
||||
(company-set-selection 0)
|
||||
(setq company-selection-changed nil)
|
||||
(company-call-frontends 'update)
|
||||
t)
|
||||
)))
|
||||
|
||||
(defun company-tng--adjust-tooltip-highlight (args)
|
||||
"Prevent the tooltip from highlighting the current selection if it wasn't
|
||||
made explicitly (i.e. `company-selection-changed' is true)"
|
||||
(unless company-selection-changed
|
||||
;; The 4th arg of `company-fill-propertize' is selected
|
||||
(setf (nth 3 args) nil))
|
||||
args)
|
||||
|
||||
(defun company-tng--supress-post-completion (command &rest args)
|
||||
"Installed as a :before-until advice on `company-call-backend' and
|
||||
prevents the 'post-completion command from being delivered to the backend
|
||||
for the next iteration. post-completion do things like expand snippets
|
||||
which are undesirable because completions are implicit in company-tng and
|
||||
visible side-effects after the completion are surprising."
|
||||
(when (eq command 'post-completion)
|
||||
(advice-remove 'company-call-backend 'company-tng--supress-post-completion)
|
||||
t))
|
||||
|
||||
(provide 'company-tng)
|
||||
;;; company-tng.el ends here
|
Binary file not shown.
|
@ -0,0 +1,123 @@
|
|||
;;; company-xcode.el --- company-mode completion backend for Xcode projects
|
||||
|
||||
;; Copyright (C) 2009-2011, 2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nikolaj Schumacher
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-xcode nil
|
||||
"Completion backend for Xcode projects."
|
||||
:group 'company)
|
||||
|
||||
(defcustom company-xcode-xcodeindex-executable (executable-find "xcodeindex")
|
||||
"Location of xcodeindex executable."
|
||||
:type 'file)
|
||||
|
||||
(defvar company-xcode-tags nil)
|
||||
|
||||
(defun company-xcode-reset ()
|
||||
"Reset the cached tags."
|
||||
(interactive)
|
||||
(setq company-xcode-tags nil))
|
||||
|
||||
(defcustom company-xcode-types
|
||||
'("Class" "Constant" "Enum" "Macro" "Modeled Class" "Structure"
|
||||
"Type" "Union" "Function")
|
||||
"The types of symbols offered by `company-xcode'.
|
||||
No context-enabled completion is available. Types like methods will be
|
||||
offered regardless of whether the class supports them. The defaults should be
|
||||
valid in most contexts."
|
||||
:set (lambda (variable value)
|
||||
(set variable value)
|
||||
(company-xcode-reset))
|
||||
:type '(set (const "Category") (const "Class") (const "Class Method")
|
||||
(const "Class Variable") (const "Constant") (const "Enum")
|
||||
(const "Field") (const "Instance Method")
|
||||
(const "Instance Variable") (const "Macro")
|
||||
(const "Modeled Class") (const "Modeled Method")
|
||||
(const "Modeled Property") (const "Property") (const "Protocol")
|
||||
(const "Structure") (const "Type") (const "Union")
|
||||
(const "Variable") (const "Function")))
|
||||
|
||||
(defvar-local company-xcode-project 'unknown)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defun company-xcode-fetch (project-bundle)
|
||||
(setq project-bundle (directory-file-name project-bundle))
|
||||
(message "Retrieving dump from %s..." project-bundle)
|
||||
(with-temp-buffer
|
||||
(let ((default-directory (file-name-directory project-bundle)))
|
||||
(call-process company-xcode-xcodeindex-executable nil (current-buffer)
|
||||
nil "dump" "-project"
|
||||
(file-name-nondirectory project-bundle) "-quiet")
|
||||
(goto-char (point-min))
|
||||
(let ((regexp (concat "^\\([^\t\n]*\\)\t[^\t\n]*\t"
|
||||
(regexp-opt company-xcode-types)
|
||||
"\t[^\t\n]*\t[^\t\n]*"))
|
||||
candidates)
|
||||
(while (re-search-forward regexp nil t)
|
||||
(cl-pushnew (match-string 1) candidates :test #'equal))
|
||||
(message "Retrieving dump from %s...done" project-bundle)
|
||||
candidates))))
|
||||
|
||||
(defun company-xcode-find-project ()
|
||||
(let ((dir (if buffer-file-name
|
||||
(file-name-directory buffer-file-name)
|
||||
(expand-file-name default-directory)))
|
||||
(prev-dir nil)
|
||||
file)
|
||||
(while (not (or file (equal dir prev-dir)))
|
||||
(setq file (car (directory-files dir t ".xcodeproj\\'" t))
|
||||
prev-dir dir
|
||||
dir (file-name-directory (directory-file-name dir))))
|
||||
file))
|
||||
|
||||
(defun company-xcode-tags ()
|
||||
(when (eq company-xcode-project 'unknown)
|
||||
(setq company-xcode-project (company-xcode-find-project)))
|
||||
(when company-xcode-project
|
||||
(cdr (or (assoc company-xcode-project company-xcode-tags)
|
||||
(car (push (cons company-xcode-project
|
||||
(company-xcode-fetch company-xcode-project))
|
||||
company-xcode-tags))))))
|
||||
;;;###autoload
|
||||
(defun company-xcode (command &optional arg &rest ignored)
|
||||
"`company-mode' completion backend for Xcode projects."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-xcode))
|
||||
(prefix (and company-xcode-xcodeindex-executable
|
||||
(company-xcode-tags)
|
||||
(not (company-in-string-or-comment))
|
||||
(or (company-grab-symbol) 'stop)))
|
||||
(candidates (let ((completion-ignore-case nil))
|
||||
(company-xcode-tags)
|
||||
(all-completions arg (company-xcode-tags))))))
|
||||
|
||||
|
||||
(provide 'company-xcode)
|
||||
;;; company-xcode.el ends here
|
Binary file not shown.
|
@ -0,0 +1,147 @@
|
|||
;;; company-yasnippet.el --- company-mode completion backend for Yasnippet
|
||||
|
||||
;; Copyright (C) 2014, 2015 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Dmitry Gutov
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company)
|
||||
(require 'cl-lib)
|
||||
|
||||
(declare-function yas--table-hash "yasnippet")
|
||||
(declare-function yas--get-snippet-tables "yasnippet")
|
||||
(declare-function yas-expand-snippet "yasnippet")
|
||||
(declare-function yas--template-content "yasnippet")
|
||||
(declare-function yas--template-expand-env "yasnippet")
|
||||
(declare-function yas--warning "yasnippet")
|
||||
|
||||
(defun company-yasnippet--key-prefixes ()
|
||||
;; Mostly copied from `yas--templates-for-key-at-point'.
|
||||
(defvar yas-key-syntaxes)
|
||||
(save-excursion
|
||||
(let ((original (point))
|
||||
(methods yas-key-syntaxes)
|
||||
prefixes
|
||||
method)
|
||||
(while methods
|
||||
(unless (eq method (car methods))
|
||||
(goto-char original))
|
||||
(setq method (car methods))
|
||||
(cond ((stringp method)
|
||||
(skip-syntax-backward method)
|
||||
(setq methods (cdr methods)))
|
||||
((functionp method)
|
||||
(unless (eq (funcall method original)
|
||||
'again)
|
||||
(setq methods (cdr methods))))
|
||||
(t
|
||||
(setq methods (cdr methods))
|
||||
(yas--warning "Invalid element `%s' in `yas-key-syntaxes'" method)))
|
||||
(let ((prefix (buffer-substring-no-properties (point) original)))
|
||||
(unless (equal prefix (car prefixes))
|
||||
(push prefix prefixes))))
|
||||
prefixes)))
|
||||
|
||||
(defun company-yasnippet--candidates (prefix)
|
||||
;; Process the prefixes in reverse: unlike Yasnippet, we look for prefix
|
||||
;; matches, so the longest prefix with any matches should be the most useful.
|
||||
(cl-loop with tables = (yas--get-snippet-tables)
|
||||
for key-prefix in (company-yasnippet--key-prefixes)
|
||||
;; Only consider keys at least as long as the symbol at point.
|
||||
when (>= (length key-prefix) (length prefix))
|
||||
thereis (company-yasnippet--completions-for-prefix prefix
|
||||
key-prefix
|
||||
tables)))
|
||||
|
||||
(defun company-yasnippet--completions-for-prefix (prefix key-prefix tables)
|
||||
(cl-mapcan
|
||||
(lambda (table)
|
||||
(let ((keyhash (yas--table-hash table))
|
||||
res)
|
||||
(when keyhash
|
||||
(maphash
|
||||
(lambda (key value)
|
||||
(when (and (stringp key)
|
||||
(string-prefix-p key-prefix key))
|
||||
(maphash
|
||||
(lambda (name template)
|
||||
(push
|
||||
(propertize key
|
||||
'yas-annotation name
|
||||
'yas-template template
|
||||
'yas-prefix-offset (- (length key-prefix)
|
||||
(length prefix)))
|
||||
res))
|
||||
value)))
|
||||
keyhash))
|
||||
res))
|
||||
tables))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-yasnippet (command &optional arg &rest ignore)
|
||||
"`company-mode' backend for `yasnippet'.
|
||||
|
||||
This backend should be used with care, because as long as there are
|
||||
snippets defined for the current major mode, this backend will always
|
||||
shadow backends that come after it. Recommended usages:
|
||||
|
||||
* In a buffer-local value of `company-backends', grouped with a backend or
|
||||
several that provide actual text completions.
|
||||
|
||||
(add-hook 'js-mode-hook
|
||||
(lambda ()
|
||||
(set (make-local-variable 'company-backends)
|
||||
'((company-dabbrev-code company-yasnippet)))))
|
||||
|
||||
* After keyword `:with', grouped with other backends.
|
||||
|
||||
(push '(company-semantic :with company-yasnippet) company-backends)
|
||||
|
||||
* Not in `company-backends', just bound to a key.
|
||||
|
||||
(global-set-key (kbd \"C-c y\") 'company-yasnippet)
|
||||
"
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-yasnippet))
|
||||
(prefix
|
||||
;; Should probably use `yas--current-key', but that's bound to be slower.
|
||||
;; How many trigger keys start with non-symbol characters anyway?
|
||||
(and (bound-and-true-p yas-minor-mode)
|
||||
(company-grab-symbol)))
|
||||
(annotation
|
||||
(concat
|
||||
(unless company-tooltip-align-annotations " -> ")
|
||||
(get-text-property 0 'yas-annotation arg)))
|
||||
(candidates (company-yasnippet--candidates arg))
|
||||
(no-cache t)
|
||||
(post-completion
|
||||
(let ((template (get-text-property 0 'yas-template arg))
|
||||
(prefix-offset (get-text-property 0 'yas-prefix-offset arg)))
|
||||
(yas-expand-snippet (yas--template-content template)
|
||||
(- (point) (length arg) prefix-offset)
|
||||
(point)
|
||||
(yas--template-expand-env template))))))
|
||||
|
||||
(provide 'company-yasnippet)
|
||||
;;; company-yasnippet.el ends here
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,22 @@
|
|||
;;; concurrent-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'load-path (directory-file-name
|
||||
(or (file-name-directory #$) (car load-path))))
|
||||
|
||||
|
||||
;;;### (autoloads nil "concurrent" "concurrent.el" (0 0 0 0))
|
||||
;;; Generated autoloads from concurrent.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "concurrent" '("cc:")))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
;;; concurrent-autoloads.el ends here
|
|
@ -0,0 +1,2 @@
|
|||
;;; -*- no-byte-compile: t -*-
|
||||
(define-package "concurrent" "20161229.330" "Concurrent utility functions for emacs lisp" '((emacs "24.3") (deferred "0.5.0")) :commit "2239671d94b38d92e9b28d4e12fd79814cfb9c16" :keywords '("deferred" "async" "concurrent") :authors '(("SAKURAI Masashi <m.sakurai at kiwanami.net>")) :maintainer '("SAKURAI Masashi <m.sakurai at kiwanami.net>") :url "https://github.com/kiwanami/emacs-deferred/blob/master/README-concurrent.markdown")
|
|
@ -0,0 +1,502 @@
|
|||
;;; concurrent.el --- Concurrent utility functions for emacs lisp -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2010-2016 SAKURAI Masashi
|
||||
|
||||
;; Author: SAKURAI Masashi <m.sakurai at kiwanami.net>
|
||||
;; Version: 0.5.0
|
||||
;; Package-Version: 20161229.330
|
||||
;; Keywords: deferred, async, concurrent
|
||||
;; Package-Requires: ((emacs "24.3") (deferred "0.5.0"))
|
||||
;; URL: https://github.com/kiwanami/emacs-deferred/blob/master/README-concurrent.markdown
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; 'concurrent.el' is a higher level library for concurrent tasks
|
||||
;; based on 'deferred.el'. This library has following features:
|
||||
;;
|
||||
;; - Generator
|
||||
;; - Green thread
|
||||
;; - Semaphore
|
||||
;; - Dataflow
|
||||
;; - Signal/Channel
|
||||
|
||||
(require 'cl-lib)
|
||||
|
||||
(require 'deferred)
|
||||
|
||||
(defvar cc:version nil "version number")
|
||||
(setq cc:version "0.3")
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
|
||||
(defmacro cc:aif (test-form then-form &rest else-forms)
|
||||
(declare (debug (form form &rest form)))
|
||||
`(let ((it ,test-form))
|
||||
(if it ,then-form ,@else-forms)))
|
||||
(put 'cc:aif 'lisp-indent-function 2)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Generator
|
||||
|
||||
(defun cc:generator-replace-yield (tree)
|
||||
"[internal] Replace `yield' symbols to calling a function in TREE."
|
||||
(let (ret)
|
||||
(cl-loop for i in tree
|
||||
do (cond
|
||||
((eq i 'yield)
|
||||
(push 'funcall ret)
|
||||
(push i ret))
|
||||
((listp i)
|
||||
(push (cc:generator-replace-yield i) ret))
|
||||
(t
|
||||
(push i ret))))
|
||||
(nreverse ret)))
|
||||
|
||||
(defun cc:generator-line (chain line)
|
||||
"[internal] Return a macro expansion to execute the sexp LINE
|
||||
asynchronously."
|
||||
(cond
|
||||
;; function object
|
||||
((functionp line)
|
||||
`(setq ,chain (deferred:nextc ,chain ,line)))
|
||||
;; while loop form
|
||||
((eq 'while (car line))
|
||||
(let ((condition (cadr line))
|
||||
(body (cddr line)))
|
||||
`(setq ,chain
|
||||
(deferred:nextc ,chain
|
||||
(deferred:lambda (x)
|
||||
(if ,condition
|
||||
(deferred:nextc
|
||||
(progn
|
||||
,@(cc:generator-replace-yield body)) self)))))))
|
||||
;; statement
|
||||
(t
|
||||
`(setq ,chain
|
||||
(deferred:nextc ,chain
|
||||
(deferred:lambda (x) ,(cc:generator-replace-yield line)))))))
|
||||
|
||||
(defmacro cc:generator (callback &rest body)
|
||||
"Create a generator object. If BODY has `yield' symbols, it
|
||||
means calling callback function CALLBACK."
|
||||
(let ((chain (cl-gensym))
|
||||
(cc (cl-gensym))
|
||||
(waiter (cl-gensym)))
|
||||
`(let* (,chain
|
||||
(,cc ,callback)
|
||||
(,waiter (deferred:new))
|
||||
(yield (lambda (x) (funcall ,cc x) ,waiter)))
|
||||
(setq ,chain ,waiter)
|
||||
,@(cl-loop for i in body
|
||||
collect
|
||||
(cc:generator-line chain i))
|
||||
(lambda () (deferred:callback ,waiter)))))
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Thread
|
||||
|
||||
(defun cc:thread-line (wait-time chain line)
|
||||
"[internal] Return a macro expansion to execute the sexp LINE asynchronously.
|
||||
WAIT-TIME is an interval time between tasks.
|
||||
CHAIN is the previous deferred task."
|
||||
(cond
|
||||
;; function object
|
||||
((functionp line)
|
||||
`(setq ,chain (deferred:nextc ,chain ,line)))
|
||||
;; while loop form
|
||||
((eq 'while (car line))
|
||||
(let ((condition (cadr line))
|
||||
(body (cddr line))
|
||||
(retsym (cl-gensym)))
|
||||
`(setq ,chain
|
||||
(deferred:nextc ,chain
|
||||
(deferred:lambda (x)
|
||||
(if ,condition
|
||||
(deferred:nextc
|
||||
(let ((,retsym (progn ,@body)))
|
||||
(if (deferred-p ,retsym) ,retsym
|
||||
(deferred:wait ,wait-time)))
|
||||
self)))))))
|
||||
;; statement
|
||||
(t
|
||||
`(setq ,chain
|
||||
(deferred:nextc ,chain
|
||||
(lambda (x) ,line))))))
|
||||
|
||||
(defmacro cc:thread (wait-time-msec &rest body)
|
||||
"Return a thread object."
|
||||
(let ((chain (cl-gensym))
|
||||
(dstart (cl-gensym)))
|
||||
`(let* (,chain
|
||||
(,dstart (deferred:new)))
|
||||
(setq ,chain ,dstart)
|
||||
,@(cl-loop for i in body
|
||||
collect
|
||||
(cc:thread-line wait-time-msec chain i))
|
||||
(deferred:callback ,dstart))))
|
||||
(put 'cc:thread 'lisp-indent-function 1)
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Semaphore
|
||||
|
||||
(cl-defstruct cc:semaphore max-permits permits waiting-deferreds)
|
||||
|
||||
(defun cc:semaphore-create(permits-num)
|
||||
"Return a semaphore object with PERMITS-NUM permissions."
|
||||
(make-cc:semaphore :max-permits permits-num :permits permits-num))
|
||||
|
||||
(defun cc:semaphore-acquire(semaphore)
|
||||
"Acquire an execution permission and return deferred object to chain.
|
||||
If this semaphore object has permissions, the subsequent deferred
|
||||
task is executed immediately. If this semaphore object has no
|
||||
permissions, the subsequent deferred task is blocked. After the
|
||||
permission is returned, the task is executed."
|
||||
(cond
|
||||
((< 0 (cc:semaphore-permits semaphore))
|
||||
(cl-decf (cc:semaphore-permits semaphore))
|
||||
(deferred:succeed))
|
||||
(t
|
||||
(let ((d (deferred:new)))
|
||||
(push d (cc:semaphore-waiting-deferreds semaphore))
|
||||
d))))
|
||||
|
||||
(defun cc:semaphore-release(semaphore)
|
||||
"Release an execution permission. The programmer is responsible to return the permissions."
|
||||
(when (<= (cc:semaphore-max-permits semaphore)
|
||||
(cc:semaphore-permits semaphore))
|
||||
(error "Too many calling semaphore-release. [max:%s <= permits:%s]"
|
||||
(cc:semaphore-max-permits semaphore)
|
||||
(cc:semaphore-permits semaphore)))
|
||||
(let ((waiting-deferreds
|
||||
(cc:semaphore-waiting-deferreds semaphore)))
|
||||
(cond
|
||||
(waiting-deferreds
|
||||
(let* ((d (car (last waiting-deferreds))))
|
||||
(setf (cc:semaphore-waiting-deferreds semaphore)
|
||||
(nbutlast waiting-deferreds))
|
||||
(deferred:callback-post d)))
|
||||
(t
|
||||
(cl-incf (cc:semaphore-permits semaphore)))))
|
||||
semaphore)
|
||||
|
||||
(defun cc:semaphore-with (semaphore body-func &optional error-func)
|
||||
"Execute the task BODY-FUNC asynchronously with the semaphore block."
|
||||
(deferred:try
|
||||
(deferred:nextc (cc:semaphore-acquire semaphore) body-func)
|
||||
:catch
|
||||
error-func
|
||||
:finally
|
||||
(lambda (_x) (cc:semaphore-release semaphore))))
|
||||
(put 'cc:semaphore-with 'lisp-indent-function 1)
|
||||
|
||||
(defun cc:semaphore-release-all (semaphore)
|
||||
"Release all permissions for resetting the semaphore object.
|
||||
If the semaphore object has some blocked tasks, this function
|
||||
return a list of the tasks and clear the list of the blocked
|
||||
tasks in the semaphore object."
|
||||
(setf (cc:semaphore-permits semaphore)
|
||||
(cc:semaphore-max-permits semaphore))
|
||||
(let ((ds (cc:semaphore-waiting-deferreds semaphore)))
|
||||
(when ds
|
||||
(setf (cc:semaphore-waiting-deferreds semaphore) nil))
|
||||
ds))
|
||||
|
||||
(defun cc:semaphore-interrupt-all (semaphore)
|
||||
"Clear the list of the blocked tasks in the semaphore and return a deferred object to chain.
|
||||
This function is used for the interruption cases."
|
||||
(when (cc:semaphore-waiting-deferreds semaphore)
|
||||
(setf (cc:semaphore-waiting-deferreds semaphore) nil)
|
||||
(setf (cc:semaphore-permits semaphore) 0))
|
||||
(cc:semaphore-acquire semaphore))
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Signal / Channel
|
||||
|
||||
(defun cc:signal-channel (&optional name parent-channel)
|
||||
"Create a channel.
|
||||
NAME is a channel name for debug.
|
||||
PARENT-CHANNEL is an upstream channel. The observers of this channel can receive the upstream signals.
|
||||
In the case of using the function `cc:signal-send', the observers of the upstream channel can not receive the signals of this channel. The function `cc:signal-send-global' can send a signal to the upstream channels from the downstream channels."
|
||||
(let ((ch (cons
|
||||
(or name (format "signal%s" (deferred:uid))) ; name for debug
|
||||
(cons
|
||||
parent-channel ; parent-channel
|
||||
nil)))) ; observers
|
||||
(when parent-channel
|
||||
(cc:signal-connect
|
||||
parent-channel
|
||||
t (lambda (event)
|
||||
(cl-destructuring-bind
|
||||
(event-name event-args) event
|
||||
(apply 'cc:signal-send
|
||||
ch event-name event-args)))))
|
||||
ch))
|
||||
|
||||
(defmacro cc:signal-name (ch)
|
||||
"[internal] Return signal name."
|
||||
`(car ,ch))
|
||||
|
||||
(defmacro cc:signal-parent-channel (ch)
|
||||
"[internal] Return parent channel object."
|
||||
`(cadr ,ch))
|
||||
|
||||
(defmacro cc:signal-observers (ch)
|
||||
"[internal] Return observers."
|
||||
`(cddr ,ch))
|
||||
|
||||
(defun cc:signal-connect (channel event-sym &optional callback)
|
||||
"Append an observer for EVENT-SYM of CHANNEL and return a deferred object.
|
||||
If EVENT-SYM is `t', the observer receives all signals of the channel.
|
||||
If CALLBACK function is given, the deferred object executes the
|
||||
CALLBACK function asynchronously. One can connect subsequent
|
||||
tasks to the returned deferred object."
|
||||
(let ((d (if callback
|
||||
(deferred:new callback)
|
||||
(deferred:new))))
|
||||
(push (cons event-sym d)
|
||||
(cc:signal-observers channel))
|
||||
d))
|
||||
|
||||
(defun cc:signal-send (channel event-sym &rest args)
|
||||
"Send a signal to CHANNEL. If ARGS values are given, observers can get the values by following code: (lambda (event) (destructuring-bind (event-sym (args)) event ... )). "
|
||||
(let ((observers (cc:signal-observers channel))
|
||||
(event (list event-sym args)))
|
||||
(cl-loop for i in observers
|
||||
for name = (car i)
|
||||
for d = (cdr i)
|
||||
if (or (eq event-sym name) (eq t name))
|
||||
do (deferred:callback-post d event))))
|
||||
|
||||
(defun cc:signal-send-global (channel event-sym &rest args)
|
||||
"Send a signal to the most upstream channel. "
|
||||
(cc:aif (cc:signal-parent-channel channel)
|
||||
(apply 'cc:signal-send-global it event-sym args)
|
||||
(apply 'cc:signal-send channel event-sym args)))
|
||||
|
||||
|
||||
(defun cc:signal-disconnect (channel deferred)
|
||||
"Remove the observer object DEFERRED from CHANNEL and return
|
||||
the removed deferred object. "
|
||||
(let ((observers (cc:signal-observers channel)) deleted)
|
||||
(setf
|
||||
(cc:signal-observers channel) ; place
|
||||
(cl-loop for i in observers
|
||||
for d = (cdr i)
|
||||
unless (eq d deferred)
|
||||
collect i
|
||||
else
|
||||
do (push i deleted)))
|
||||
deleted))
|
||||
|
||||
(defun cc:signal-disconnect-all (channel)
|
||||
"Remove all observers."
|
||||
(setf
|
||||
(cc:signal-observers channel) ; place
|
||||
nil))
|
||||
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Dataflow
|
||||
|
||||
;; Dataflow variable entry
|
||||
(cl-defstruct cc:dataflow key (value 'cc:dataflow-undefine) deferred-list)
|
||||
|
||||
(defun cc:dataflow-undefine-p (obj)
|
||||
"[internal] If the variable entry is not bound, return `t'."
|
||||
(eq 'cc:dataflow-undefine (cc:dataflow-value obj)))
|
||||
|
||||
(defmacro cc:dataflow-parent-environment (df)
|
||||
"[internal] Return the parent environment."
|
||||
`(car ,df))
|
||||
|
||||
(defmacro cc:dataflow-test (df)
|
||||
"[internal] Return the test function."
|
||||
`(cadr ,df))
|
||||
|
||||
(defmacro cc:dataflow-channel (df)
|
||||
"[internal] Return the channel object."
|
||||
`(cl-caddr ,df))
|
||||
|
||||
(defmacro cc:dataflow-list (df)
|
||||
"[internal] Return the list of deferred object which are waiting for value binding."
|
||||
`(cl-cdddr ,df))
|
||||
|
||||
(defun cc:dataflow-environment (&optional parent-env test-func channel)
|
||||
"Create a dataflow environment.
|
||||
PARENT-ENV is the default environment. If this environment doesn't have the entry A and the parent one has the entry A, this environment can return the entry A. One can override the entry, setting another entry A to this environment.
|
||||
TEST-FUNC is a test function that compares the entry keys. The default function is `equal'.
|
||||
CHANNEL is a channel object that sends signals of variable events. Observers can receive following signals:
|
||||
-get-first : the fist referrer is waiting for binding,
|
||||
-get-waiting : another referrer is waiting for binding,
|
||||
-set : a value is bound,
|
||||
-get : returned a bound value,
|
||||
-clear : cleared one entry,
|
||||
-clear-all : cleared all entries.
|
||||
"
|
||||
(let ((this (list parent-env
|
||||
(or test-func 'equal)
|
||||
(or channel
|
||||
(cc:signal-channel
|
||||
'dataflow
|
||||
(and parent-env
|
||||
(cc:dataflow-channel parent-env)))))))
|
||||
(cc:dataflow-init-connect this)
|
||||
this))
|
||||
|
||||
(defun cc:dataflow-init-connect (df)
|
||||
"[internal] Initialize the channel object."
|
||||
(cc:dataflow-connect
|
||||
df 'set
|
||||
(lambda (args)
|
||||
(cl-destructuring-bind (_event (key)) args
|
||||
(let* ((obj (cc:dataflow-get-object-for-value df key))
|
||||
(value (and obj (cc:dataflow-value obj))))
|
||||
(when obj
|
||||
(cl-loop for i in (cc:aif (cc:dataflow-get-object-for-deferreds df key)
|
||||
(cc:dataflow-deferred-list it) nil)
|
||||
do (deferred:callback-post i value))
|
||||
(setf (cc:dataflow-deferred-list obj) nil)))))))
|
||||
|
||||
(defun cc:dataflow-get-object-for-value (df key)
|
||||
"[internal] Return an entry object that is indicated by KEY.
|
||||
If the environment DF doesn't have the entry and the parent one has the entry, this function returns the entry of the parent environment. This function doesn't affect the waiting list."
|
||||
(or
|
||||
(cl-loop for i in (cc:dataflow-list df)
|
||||
with test = (cc:dataflow-test df)
|
||||
if (and (funcall test key (cc:dataflow-key i))
|
||||
(not (cc:dataflow-undefine-p i)))
|
||||
return i)
|
||||
(deferred:aand
|
||||
(cc:dataflow-parent-environment df)
|
||||
(cc:dataflow-get-object-for-value it key))))
|
||||
|
||||
(defun cc:dataflow-get-object-for-deferreds (df key)
|
||||
"[internal] Return a list of the deferred objects those are waiting for value binding.
|
||||
This function doesn't affect the waiting list and doesn't refer the parent environment."
|
||||
(cl-loop for i in (cc:dataflow-list df)
|
||||
with test = (cc:dataflow-test df)
|
||||
if (funcall test key (cc:dataflow-key i))
|
||||
return i))
|
||||
|
||||
(defun cc:dataflow-connect (df event-sym &optional callback)
|
||||
"Append an observer for EVENT-SYM of the channel of DF and return a deferred object.
|
||||
See the docstring of `cc:dataflow-environment' for details."
|
||||
(cc:signal-connect (cc:dataflow-channel df) event-sym callback))
|
||||
|
||||
(defun cc:dataflow-signal (df event &optional arg)
|
||||
"[internal] Send a signal to the channel of DF."
|
||||
(cc:signal-send (cc:dataflow-channel df) event arg))
|
||||
|
||||
(defun cc:dataflow-get (df key)
|
||||
"Return a deferred object that can refer the value which is indicated by KEY.
|
||||
If DF has the entry that bound value, the subsequent deferred task is executed immediately.
|
||||
If not, the task is deferred till a value is bound."
|
||||
(let ((obj (cc:dataflow-get-object-for-value df key)))
|
||||
(cond
|
||||
((and obj (cc:dataflow-value obj))
|
||||
(cc:dataflow-signal df 'get key)
|
||||
(deferred:succeed (cc:dataflow-value obj)))
|
||||
(t
|
||||
(setq obj (cc:dataflow-get-object-for-deferreds df key))
|
||||
(unless obj
|
||||
(setq obj (make-cc:dataflow :key key))
|
||||
(push obj (cc:dataflow-list df))
|
||||
(cc:dataflow-signal df 'get-first key))
|
||||
(let ((d (deferred:new)))
|
||||
(push d (cc:dataflow-deferred-list obj))
|
||||
(cc:dataflow-signal df 'get-waiting key)
|
||||
d)))))
|
||||
|
||||
(defun cc:dataflow-get-sync (df key)
|
||||
"Return the value which is indicated by KEY synchronously.
|
||||
If the environment DF doesn't have an entry of KEY, this function returns nil."
|
||||
(let ((obj (cc:dataflow-get-object-for-value df key)))
|
||||
(and obj (cc:dataflow-value obj))))
|
||||
|
||||
(defun cc:dataflow-set (df key value)
|
||||
"Bind the VALUE to KEY in the environment DF.
|
||||
If DF already has the bound entry of KEY, this function throws an error signal.
|
||||
VALUE can be nil as a value."
|
||||
(let ((obj (cc:dataflow-get-object-for-deferreds df key)))
|
||||
(cond
|
||||
((and obj (not (cc:dataflow-undefine-p obj)))
|
||||
;; overwrite!
|
||||
(error "Can not set a dataflow value. The key [%s] has already had a value. NEW:[%s] OLD:[%s]" key value (cc:dataflow-value obj)))
|
||||
(obj
|
||||
(setf (cc:dataflow-value obj) value))
|
||||
(t
|
||||
;; just value arrived
|
||||
(push (make-cc:dataflow :key key :value value)
|
||||
(cc:dataflow-list df))))
|
||||
;; value arrived and start deferred objects
|
||||
(cc:dataflow-signal df 'set key)
|
||||
value))
|
||||
|
||||
(defun cc:dataflow-clear (df key)
|
||||
"Clear the entry which is indicated by KEY.
|
||||
This function does nothing for the waiting deferred objects."
|
||||
(cc:dataflow-signal df 'clear key)
|
||||
(setf (cc:dataflow-list df)
|
||||
(cl-loop for i in (cc:dataflow-list df)
|
||||
with test = (cc:dataflow-test df)
|
||||
unless (funcall test key (cc:dataflow-key i))
|
||||
collect i)))
|
||||
|
||||
(defun cc:dataflow-get-avalable-pairs (df)
|
||||
"Return an available key-value alist in the environment DF and the parent ones."
|
||||
(append
|
||||
(cl-loop for i in (cc:dataflow-list df)
|
||||
for key = (cc:dataflow-key i)
|
||||
for val = (cc:dataflow-value i)
|
||||
unless (cc:dataflow-undefine-p i) collect (cons key val))
|
||||
(deferred:aand
|
||||
(cc:dataflow-parent-environment df)
|
||||
(cc:dataflow-get-avalable-pairs it))))
|
||||
|
||||
(defun cc:dataflow-get-waiting-keys (df)
|
||||
"Return a list of keys which have waiting deferred objects in the environment DF and the parent ones."
|
||||
(append
|
||||
(cl-loop for i in (cc:dataflow-list df)
|
||||
for key = (cc:dataflow-key i)
|
||||
if (cc:dataflow-undefine-p i) collect key)
|
||||
(deferred:aand
|
||||
(cc:dataflow-parent-environment df)
|
||||
(cc:dataflow-get-waiting-keys it))))
|
||||
|
||||
(defun cc:dataflow-clear-all (df)
|
||||
"Clear all entries in the environment DF.
|
||||
This function does nothing for the waiting deferred objects."
|
||||
(cc:dataflow-signal df 'clear-all)
|
||||
(setf (cc:dataflow-list df) nil))
|
||||
|
||||
|
||||
(provide 'concurrent)
|
||||
|
||||
;; Local Variables:
|
||||
;; byte-compile-warnings: (not cl-functions)
|
||||
;; End:
|
||||
|
||||
;;; concurrent.el ends here
|
Binary file not shown.
|
@ -0,0 +1,22 @@
|
|||
;;; ctable-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'load-path (directory-file-name
|
||||
(or (file-name-directory #$) (car load-path))))
|
||||
|
||||
|
||||
;;;### (autoloads nil "ctable" "ctable.el" (0 0 0 0))
|
||||
;;; Generated autoloads from ctable.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "ctable" '("ctbl:")))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
;;; ctable-autoloads.el ends here
|
|
@ -0,0 +1,2 @@
|
|||
;;; -*- no-byte-compile: t -*-
|
||||
(define-package "ctable" "20171006.11" "Table component for Emacs Lisp" 'nil :commit "b8830d1ca95abb100a81bc32011bd17d5ecba000" :keywords '("table") :authors '(("SAKURAI Masashi <m.sakurai at kiwanami.net>")) :maintainer '("SAKURAI Masashi <m.sakurai at kiwanami.net>") :url "https://github.com/kiwanami/emacs-ctable")
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,22 @@
|
|||
;;; deferred-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'load-path (directory-file-name
|
||||
(or (file-name-directory #$) (car load-path))))
|
||||
|
||||
|
||||
;;;### (autoloads nil "deferred" "deferred.el" (0 0 0 0))
|
||||
;;; Generated autoloads from deferred.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "deferred" '("deferred:")))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
;;; deferred-autoloads.el ends here
|
|
@ -0,0 +1,2 @@
|
|||
;;; -*- no-byte-compile: t -*-
|
||||
(define-package "deferred" "20170901.1330" "Simple asynchronous functions for emacs lisp" '((emacs "24.4")) :commit "2239671d94b38d92e9b28d4e12fd79814cfb9c16" :keywords '("deferred" "async") :authors '(("SAKURAI Masashi <m.sakurai at kiwanami.net>")) :maintainer '("SAKURAI Masashi <m.sakurai at kiwanami.net>") :url "https://github.com/kiwanami/emacs-deferred")
|
|
@ -0,0 +1,972 @@
|
|||
;;; deferred.el --- Simple asynchronous functions for emacs lisp -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2010-2016 SAKURAI Masashi
|
||||
|
||||
;; Author: SAKURAI Masashi <m.sakurai at kiwanami.net>
|
||||
;; Version: 0.5.1
|
||||
;; Package-Version: 20170901.1330
|
||||
;; Keywords: deferred, async
|
||||
;; Package-Requires: ((emacs "24.4"))
|
||||
;; URL: https://github.com/kiwanami/emacs-deferred
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; 'deferred.el' is a simple library for asynchronous tasks.
|
||||
;; [https://github.com/kiwanami/emacs-deferred]
|
||||
|
||||
;; The API is almost the same as JSDeferred written by cho45. See the
|
||||
;; JSDeferred and Mochikit.Async web sites for further documentations.
|
||||
;; [https://github.com/cho45/jsdeferred]
|
||||
;; [http://mochikit.com/doc/html/MochiKit/Async.html]
|
||||
|
||||
;; A good introduction document (JavaScript)
|
||||
;; [http://cho45.stfuawsc.com/jsdeferred/doc/intro.en.html]
|
||||
|
||||
;;; Samples:
|
||||
|
||||
;; ** HTTP Access
|
||||
|
||||
;; (require 'url)
|
||||
;; (deferred:$
|
||||
;; (deferred:url-retrieve "http://www.gnu.org")
|
||||
;; (deferred:nextc it
|
||||
;; (lambda (buf)
|
||||
;; (insert (with-current-buffer buf (buffer-string)))
|
||||
;; (kill-buffer buf))))
|
||||
|
||||
;; ** Invoking command tasks
|
||||
|
||||
;; (deferred:$
|
||||
;; (deferred:process "wget" "-O" "a.jpg" "http://www.gnu.org/software/emacs/tour/images/splash.png")
|
||||
;; (deferred:nextc it
|
||||
;; (lambda (x) (deferred:process "convert" "a.jpg" "-resize" "100x100" "jpg:b.jpg")))
|
||||
;; (deferred:nextc it
|
||||
;; (lambda (x)
|
||||
;; (insert-image (create-image (expand-file-name "b.jpg") 'jpeg nil)))))
|
||||
|
||||
;; See the readme for further API documentation.
|
||||
|
||||
;; ** Applications
|
||||
|
||||
;; *Inertial scrolling for Emacs
|
||||
;; [https://github.com/kiwanami/emacs-inertial-scroll]
|
||||
|
||||
;; This program makes simple multi-thread function, using
|
||||
;; deferred.el.
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'subr-x)
|
||||
|
||||
(declare-function pp-display-expression 'pp)
|
||||
|
||||
(defvar deferred:version nil "deferred.el version")
|
||||
(setq deferred:version "0.5.0")
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defmacro deferred:aand (test &rest rest)
|
||||
"[internal] Anaphoric AND."
|
||||
(declare (debug ("test" form &rest form)))
|
||||
`(let ((it ,test))
|
||||
(if it ,(if rest `(deferred:aand ,@rest) 'it))))
|
||||
|
||||
(defmacro deferred:$ (&rest elements)
|
||||
"Anaphoric function chain macro for deferred chains."
|
||||
(declare (debug (&rest form)))
|
||||
`(let (it)
|
||||
,@(cl-loop for i in elements
|
||||
collect
|
||||
`(setq it ,i))
|
||||
it))
|
||||
|
||||
(defmacro deferred:lambda (args &rest body)
|
||||
"Anaphoric lambda macro for self recursion."
|
||||
(declare (debug ("args" form &rest form)))
|
||||
(let ((argsyms (cl-loop repeat (length args) collect (cl-gensym))))
|
||||
`(lambda (,@argsyms)
|
||||
(let (self)
|
||||
(setq self (lambda( ,@args ) ,@body))
|
||||
(funcall self ,@argsyms)))))
|
||||
|
||||
(cl-defmacro deferred:try (d &key catch finally)
|
||||
"Try-catch-finally macro. This macro simulates the
|
||||
try-catch-finally block asynchronously. CATCH and FINALLY can be
|
||||
nil. Because of asynchrony, this macro does not ensure that the
|
||||
task FINALLY should be called."
|
||||
(let ((chain
|
||||
(if catch `((deferred:error it ,catch)))))
|
||||
(when finally
|
||||
(setq chain (append chain `((deferred:watch it ,finally)))))
|
||||
`(deferred:$ ,d ,@chain)))
|
||||
|
||||
(defun deferred:setTimeout (f msec)
|
||||
"[internal] Timer function that emulates the `setTimeout' function in JS."
|
||||
(run-at-time (/ msec 1000.0) nil f))
|
||||
|
||||
(defun deferred:cancelTimeout (id)
|
||||
"[internal] Timer cancellation function that emulates the `cancelTimeout' function in JS."
|
||||
(cancel-timer id))
|
||||
|
||||
(defun deferred:run-with-idle-timer (sec f)
|
||||
"[internal] Wrapper function for run-with-idle-timer."
|
||||
(run-with-idle-timer sec nil f))
|
||||
|
||||
(defun deferred:call-lambda (f &optional arg)
|
||||
"[internal] Call a function with one or zero argument safely.
|
||||
The lambda function can define with zero and one argument."
|
||||
(condition-case err
|
||||
(funcall f arg)
|
||||
('wrong-number-of-arguments
|
||||
(display-warning 'deferred "\
|
||||
Callback that takes no argument may be specified.
|
||||
Passing callback with no argument is deprecated.
|
||||
Callback must take one argument.
|
||||
Or, this error is coming from somewhere inside of the callback: %S" err)
|
||||
(condition-case nil
|
||||
(funcall f)
|
||||
('wrong-number-of-arguments
|
||||
(signal 'wrong-number-of-arguments (cdr err))))))) ; return the first error
|
||||
|
||||
;; debug
|
||||
|
||||
(eval-and-compile
|
||||
(defvar deferred:debug nil "Debug output switch."))
|
||||
(defvar deferred:debug-count 0 "[internal] Debug output counter.")
|
||||
|
||||
(defmacro deferred:message (&rest args)
|
||||
"[internal] Debug log function."
|
||||
(when deferred:debug
|
||||
`(progn
|
||||
(with-current-buffer (get-buffer-create "*deferred:debug*")
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(insert (format "%5i %s\n" deferred:debug-count (format ,@args)))))
|
||||
(cl-incf deferred:debug-count))))
|
||||
|
||||
(defun deferred:message-mark ()
|
||||
"[internal] Debug log function."
|
||||
(interactive)
|
||||
(deferred:message "==================== mark ==== %s"
|
||||
(format-time-string "%H:%M:%S" (current-time))))
|
||||
|
||||
(defun deferred:pp (d)
|
||||
(require 'pp)
|
||||
(deferred:$
|
||||
(deferred:nextc d
|
||||
(lambda (x)
|
||||
(pp-display-expression x "*deferred:pp*")))
|
||||
(deferred:error it
|
||||
(lambda (e)
|
||||
(pp-display-expression e "*deferred:pp*")))
|
||||
(deferred:nextc it
|
||||
(lambda (_x) (pop-to-buffer "*deferred:pp*")))))
|
||||
|
||||
(defvar deferred:debug-on-signal nil
|
||||
"If non nil, the value `debug-on-signal' is substituted this
|
||||
value in the `condition-case' form in deferred
|
||||
implementations. Then, Emacs debugger can catch an error occurred
|
||||
in the asynchronous tasks.")
|
||||
|
||||
(defmacro deferred:condition-case (var protected-form &rest handlers)
|
||||
"[internal] Custom condition-case. See the comment for
|
||||
`deferred:debug-on-signal'."
|
||||
(declare (debug condition-case)
|
||||
(indent 2))
|
||||
`(let ((debug-on-signal
|
||||
(or debug-on-signal deferred:debug-on-signal)))
|
||||
(condition-case ,var
|
||||
,protected-form
|
||||
,@handlers)))
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Back end functions of deferred tasks
|
||||
|
||||
(defvar deferred:tick-time 0.001
|
||||
"Waiting time between asynchronous tasks (second).
|
||||
The shorter waiting time increases the load of Emacs. The end
|
||||
user can tune this parameter. However, applications should not
|
||||
modify it because the applications run on various environments.")
|
||||
|
||||
(defvar deferred:queue nil
|
||||
"[internal] The execution queue of deferred objects.
|
||||
See the functions `deferred:post-task' and `deferred:worker'.")
|
||||
|
||||
(defmacro deferred:pack (a b c)
|
||||
`(cons ,a (cons ,b ,c)))
|
||||
|
||||
(defun deferred:schedule-worker ()
|
||||
"[internal] Schedule consuming a deferred task in the execution queue."
|
||||
(run-at-time deferred:tick-time nil 'deferred:worker))
|
||||
|
||||
(defun deferred:post-task (d which &optional arg)
|
||||
"[internal] Add a deferred object to the execution queue
|
||||
`deferred:queue' and schedule to execute.
|
||||
D is a deferred object. WHICH is a symbol, `ok' or `ng'. ARG is
|
||||
an argument value for execution of the deferred task."
|
||||
(push (deferred:pack d which arg) deferred:queue)
|
||||
(deferred:message "QUEUE-POST [%s]: %s"
|
||||
(length deferred:queue) (deferred:pack d which arg))
|
||||
(deferred:schedule-worker)
|
||||
d)
|
||||
|
||||
(defun deferred:clear-queue ()
|
||||
"Clear the execution queue. For test and debugging."
|
||||
(interactive)
|
||||
(deferred:message "QUEUE-CLEAR [%s -> 0]" (length deferred:queue))
|
||||
(setq deferred:queue nil))
|
||||
|
||||
(defun deferred:worker ()
|
||||
"[internal] Consume a deferred task.
|
||||
Mainly this function is called by timer asynchronously."
|
||||
(when deferred:queue
|
||||
(let* ((pack (car (last deferred:queue)))
|
||||
(d (car pack))
|
||||
(which (cadr pack))
|
||||
(arg (cddr pack)) value)
|
||||
(setq deferred:queue (nbutlast deferred:queue))
|
||||
(condition-case err
|
||||
(setq value (deferred:exec-task d which arg))
|
||||
(error
|
||||
(deferred:message "ERROR : %s" err)
|
||||
(message "deferred error : %s" err)))
|
||||
value)))
|
||||
|
||||
(defun deferred:flush-queue! ()
|
||||
"Call all deferred tasks synchronously. For test and debugging."
|
||||
(let (value)
|
||||
(while deferred:queue
|
||||
(setq value (deferred:worker)))
|
||||
value))
|
||||
|
||||
(defun deferred:sync! (d)
|
||||
"Wait for the given deferred task. For test and debugging.
|
||||
Error is raised if it is not processed within deferred chain D."
|
||||
(progn
|
||||
(let ((last-value 'deferred:undefined*)
|
||||
uncaught-error)
|
||||
(deferred:try
|
||||
(deferred:nextc d
|
||||
(lambda (x) (setq last-value x)))
|
||||
:catch
|
||||
(lambda (err) (setq uncaught-error err)))
|
||||
(while (and (eq 'deferred:undefined* last-value)
|
||||
(not uncaught-error))
|
||||
(sit-for 0.05)
|
||||
(sleep-for 0.05))
|
||||
(when uncaught-error
|
||||
(deferred:resignal uncaught-error))
|
||||
last-value)))
|
||||
|
||||
|
||||
|
||||
;; Struct: deferred
|
||||
;;
|
||||
;; callback : a callback function (default `deferred:default-callback')
|
||||
;; errorback : an errorback function (default `deferred:default-errorback')
|
||||
;; cancel : a canceling function (default `deferred:default-cancel')
|
||||
;; next : a next chained deferred object (default nil)
|
||||
;; status : if 'ok or 'ng, this deferred has a result (error) value. (default nil)
|
||||
;; value : saved value (default nil)
|
||||
;;
|
||||
(cl-defstruct deferred
|
||||
(callback 'deferred:default-callback)
|
||||
(errorback 'deferred:default-errorback)
|
||||
(cancel 'deferred:default-cancel)
|
||||
next status value)
|
||||
|
||||
(defun deferred:default-callback (i)
|
||||
"[internal] Default callback function."
|
||||
(identity i))
|
||||
|
||||
(defun deferred:default-errorback (err)
|
||||
"[internal] Default errorback function."
|
||||
(deferred:resignal err))
|
||||
|
||||
(defun deferred:resignal (err)
|
||||
"[internal] Safely resignal ERR as an Emacs condition.
|
||||
|
||||
If ERR is a cons (ERROR-SYMBOL . DATA) where ERROR-SYMBOL has an
|
||||
`error-conditions' property, it is re-signaled unchanged. If ERR
|
||||
is a string, it is signaled as a generic error using `error'.
|
||||
Otherwise, ERR is formatted into a string as if by `print' before
|
||||
raising with `error'."
|
||||
(cond ((and (listp err)
|
||||
(symbolp (car err))
|
||||
(get (car err) 'error-conditions))
|
||||
(signal (car err) (cdr err)))
|
||||
((stringp err)
|
||||
(error "%s" err))
|
||||
(t
|
||||
(error "%S" err))))
|
||||
|
||||
(defun deferred:default-cancel (d)
|
||||
"[internal] Default canceling function."
|
||||
(deferred:message "CANCEL : %s" d)
|
||||
(setf (deferred-callback d) 'deferred:default-callback)
|
||||
(setf (deferred-errorback d) 'deferred:default-errorback)
|
||||
(setf (deferred-next d) nil)
|
||||
d)
|
||||
|
||||
(defvar deferred:onerror nil
|
||||
"Default error handler. This value is nil or a function that
|
||||
have one argument for the error message.")
|
||||
|
||||
(defun deferred:exec-task (d which &optional arg)
|
||||
"[internal] Executing deferred task. If the deferred object has
|
||||
next deferred task or the return value is a deferred object, this
|
||||
function adds the task to the execution queue.
|
||||
D is a deferred object. WHICH is a symbol, `ok' or `ng'. ARG is
|
||||
an argument value for execution of the deferred task."
|
||||
(deferred:message "EXEC : %s / %s / %s" d which arg)
|
||||
(when (null d) (error "deferred:exec-task was given a nil."))
|
||||
(let ((callback (if (eq which 'ok)
|
||||
(deferred-callback d)
|
||||
(deferred-errorback d)))
|
||||
(next-deferred (deferred-next d)))
|
||||
(cond
|
||||
(callback
|
||||
(deferred:condition-case err
|
||||
(let ((value (deferred:call-lambda callback arg)))
|
||||
(cond
|
||||
((deferred-p value)
|
||||
(deferred:message "WAIT NEST : %s" value)
|
||||
(if next-deferred
|
||||
(deferred:set-next value next-deferred)
|
||||
value))
|
||||
(t
|
||||
(if next-deferred
|
||||
(deferred:post-task next-deferred 'ok value)
|
||||
(setf (deferred-status d) 'ok)
|
||||
(setf (deferred-value d) value)
|
||||
value))))
|
||||
(error
|
||||
(cond
|
||||
(next-deferred
|
||||
(deferred:post-task next-deferred 'ng err))
|
||||
(deferred:onerror
|
||||
(deferred:call-lambda deferred:onerror err))
|
||||
(t
|
||||
(deferred:message "ERROR : %S" err)
|
||||
(message "deferred error : %S" err)
|
||||
(setf (deferred-status d) 'ng)
|
||||
(setf (deferred-value d) err)
|
||||
err)))))
|
||||
(t ; <= (null callback)
|
||||
(cond
|
||||
(next-deferred
|
||||
(deferred:exec-task next-deferred which arg))
|
||||
((eq which 'ok) arg)
|
||||
(t ; (eq which 'ng)
|
||||
(deferred:resignal arg)))))))
|
||||
|
||||
(defun deferred:set-next (prev next)
|
||||
"[internal] Connect deferred objects."
|
||||
(setf (deferred-next prev) next)
|
||||
(cond
|
||||
((eq 'ok (deferred-status prev))
|
||||
(setf (deferred-status prev) nil)
|
||||
(let ((ret (deferred:exec-task
|
||||
next 'ok (deferred-value prev))))
|
||||
(if (deferred-p ret) ret
|
||||
next)))
|
||||
((eq 'ng (deferred-status prev))
|
||||
(setf (deferred-status prev) nil)
|
||||
(let ((ret (deferred:exec-task next 'ng (deferred-value prev))))
|
||||
(if (deferred-p ret) ret
|
||||
next)))
|
||||
(t
|
||||
next)))
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Basic functions for deferred objects
|
||||
|
||||
(defun deferred:new (&optional callback)
|
||||
"Create a deferred object."
|
||||
(if callback
|
||||
(make-deferred :callback callback)
|
||||
(make-deferred)))
|
||||
|
||||
(defun deferred:callback (d &optional arg)
|
||||
"Start deferred chain with a callback message."
|
||||
(deferred:exec-task d 'ok arg))
|
||||
|
||||
(defun deferred:errorback (d &optional arg)
|
||||
"Start deferred chain with an errorback message."
|
||||
(deferred:exec-task d 'ng arg))
|
||||
|
||||
(defun deferred:callback-post (d &optional arg)
|
||||
"Add the deferred object to the execution queue."
|
||||
(deferred:post-task d 'ok arg))
|
||||
|
||||
(defun deferred:errorback-post (d &optional arg)
|
||||
"Add the deferred object to the execution queue."
|
||||
(deferred:post-task d 'ng arg))
|
||||
|
||||
(defun deferred:cancel (d)
|
||||
"Cancel all callbacks and deferred chain in the deferred object."
|
||||
(deferred:message "CANCEL : %s" d)
|
||||
(funcall (deferred-cancel d) d)
|
||||
d)
|
||||
|
||||
(defun deferred:status (d)
|
||||
"Return a current status of the deferred object. The returned value means following:
|
||||
`ok': the callback was called and waiting for next deferred.
|
||||
`ng': the errorback was called and waiting for next deferred.
|
||||
nil: The neither callback nor errorback was not called."
|
||||
(deferred-status d))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Basic utility functions
|
||||
|
||||
(defun deferred:succeed (&optional arg)
|
||||
"Create a synchronous deferred object."
|
||||
(let ((d (deferred:new)))
|
||||
(deferred:exec-task d 'ok arg)
|
||||
d))
|
||||
|
||||
(defun deferred:fail (&optional arg)
|
||||
"Create a synchronous deferred object."
|
||||
(let ((d (deferred:new)))
|
||||
(deferred:exec-task d 'ng arg)
|
||||
d))
|
||||
|
||||
(defun deferred:next (&optional callback arg)
|
||||
"Create a deferred object and schedule executing. This function
|
||||
is a short cut of following code:
|
||||
(deferred:callback-post (deferred:new callback))."
|
||||
(let ((d (if callback
|
||||
(make-deferred :callback callback)
|
||||
(make-deferred))))
|
||||
(deferred:callback-post d arg)
|
||||
d))
|
||||
|
||||
(defun deferred:nextc (d callback)
|
||||
"Create a deferred object with OK callback and connect it to the given deferred object."
|
||||
(let ((nd (make-deferred :callback callback)))
|
||||
(deferred:set-next d nd)))
|
||||
|
||||
(defun deferred:error (d callback)
|
||||
"Create a deferred object with errorback and connect it to the given deferred object."
|
||||
(let ((nd (make-deferred :errorback callback)))
|
||||
(deferred:set-next d nd)))
|
||||
|
||||
(defun deferred:watch (d callback)
|
||||
"Create a deferred object with watch task and connect it to the given deferred object.
|
||||
The watch task CALLBACK can not affect deferred chains with
|
||||
return values. This function is used in following purposes,
|
||||
simulation of try-finally block in asynchronous tasks, progress
|
||||
monitoring of tasks."
|
||||
(let* ((callback callback)
|
||||
(normal (lambda (x) (ignore-errors (deferred:call-lambda callback x)) x))
|
||||
(err (lambda (e)
|
||||
(ignore-errors (deferred:call-lambda callback e))
|
||||
(deferred:resignal e))))
|
||||
(let ((nd (make-deferred :callback normal :errorback err)))
|
||||
(deferred:set-next d nd))))
|
||||
|
||||
(defun deferred:wait (msec)
|
||||
"Return a deferred object scheduled at MSEC millisecond later."
|
||||
(let ((d (deferred:new)) (start-time (float-time)) timer)
|
||||
(deferred:message "WAIT : %s" msec)
|
||||
(setq timer (deferred:setTimeout
|
||||
(lambda ()
|
||||
(deferred:exec-task d 'ok
|
||||
(* 1000.0 (- (float-time) start-time)))
|
||||
nil) msec))
|
||||
(setf (deferred-cancel d)
|
||||
(lambda (x)
|
||||
(deferred:cancelTimeout timer)
|
||||
(deferred:default-cancel x)))
|
||||
d))
|
||||
|
||||
(defun deferred:wait-idle (msec)
|
||||
"Return a deferred object which will run when Emacs has been
|
||||
idle for MSEC millisecond."
|
||||
(let ((d (deferred:new)) (start-time (float-time)) timer)
|
||||
(deferred:message "WAIT-IDLE : %s" msec)
|
||||
(setq timer
|
||||
(deferred:run-with-idle-timer
|
||||
(/ msec 1000.0)
|
||||
(lambda ()
|
||||
(deferred:exec-task d 'ok
|
||||
(* 1000.0 (- (float-time) start-time)))
|
||||
nil)))
|
||||
(setf (deferred-cancel d)
|
||||
(lambda (x)
|
||||
(deferred:cancelTimeout timer)
|
||||
(deferred:default-cancel x)))
|
||||
d))
|
||||
|
||||
(defun deferred:call (f &rest args)
|
||||
"Call the given function asynchronously."
|
||||
(deferred:next
|
||||
(lambda (_x)
|
||||
(apply f args))))
|
||||
|
||||
(defun deferred:apply (f &optional args)
|
||||
"Call the given function asynchronously."
|
||||
(deferred:next
|
||||
(lambda (_x)
|
||||
(apply f args))))
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Utility functions
|
||||
|
||||
(defun deferred:empty-p (times-or-seq)
|
||||
"[internal] Return non-nil if TIMES-OR-SEQ is the number zero or nil."
|
||||
(or (and (numberp times-or-seq) (<= times-or-seq 0))
|
||||
(and (sequencep times-or-seq) (= (length times-or-seq) 0))))
|
||||
|
||||
(defun deferred:loop (times-or-seq func)
|
||||
"Return a iteration deferred object."
|
||||
(deferred:message "LOOP : %s" times-or-seq)
|
||||
(if (deferred:empty-p times-or-seq) (deferred:next)
|
||||
(let* (items (rd
|
||||
(cond
|
||||
((numberp times-or-seq)
|
||||
(cl-loop for i from 0 below times-or-seq
|
||||
with ld = (deferred:next)
|
||||
do
|
||||
(push ld items)
|
||||
(setq ld
|
||||
(let ((i i))
|
||||
(deferred:nextc ld
|
||||
(lambda (_x) (deferred:call-lambda func i)))))
|
||||
finally return ld))
|
||||
((sequencep times-or-seq)
|
||||
(cl-loop for i in (append times-or-seq nil) ; seq->list
|
||||
with ld = (deferred:next)
|
||||
do
|
||||
(push ld items)
|
||||
(setq ld
|
||||
(let ((i i))
|
||||
(deferred:nextc ld
|
||||
(lambda (_x) (deferred:call-lambda func i)))))
|
||||
finally return ld)))))
|
||||
(setf (deferred-cancel rd)
|
||||
(lambda (x) (deferred:default-cancel x)
|
||||
(cl-loop for i in items
|
||||
do (deferred:cancel i))))
|
||||
rd)))
|
||||
|
||||
(defun deferred:trans-multi-args (args self-func list-func main-func)
|
||||
"[internal] Check the argument values and dispatch to methods."
|
||||
(cond
|
||||
((and (= 1 (length args)) (consp (car args)) (not (functionp (car args))))
|
||||
(let ((lst (car args)))
|
||||
(cond
|
||||
((or (null lst) (null (car lst)))
|
||||
(deferred:next))
|
||||
((deferred:aand lst (car it) (or (functionp it) (deferred-p it)))
|
||||
;; a list of deferred objects
|
||||
(funcall list-func lst))
|
||||
((deferred:aand lst (consp it))
|
||||
;; an alist of deferred objects
|
||||
(funcall main-func lst))
|
||||
(t (error "Wrong argument type. %s" args)))))
|
||||
(t (funcall self-func args))))
|
||||
|
||||
(defun deferred:parallel-array-to-alist (lst)
|
||||
"[internal] Translation array to alist."
|
||||
(cl-loop for d in lst
|
||||
for i from 0 below (length lst)
|
||||
collect (cons i d)))
|
||||
|
||||
(defun deferred:parallel-alist-to-array (alst)
|
||||
"[internal] Translation alist to array."
|
||||
(cl-loop for pair in
|
||||
(sort alst (lambda (x y)
|
||||
(< (car x) (car y))))
|
||||
collect (cdr pair)))
|
||||
|
||||
(defun deferred:parallel-func-to-deferred (alst)
|
||||
"[internal] Normalization for parallel and earlier arguments."
|
||||
(cl-loop for pair in alst
|
||||
for d = (cdr pair)
|
||||
collect
|
||||
(progn
|
||||
(unless (deferred-p d)
|
||||
(setf (cdr pair) (deferred:next d)))
|
||||
pair)))
|
||||
|
||||
(defun deferred:parallel-main (alst)
|
||||
"[internal] Deferred alist implementation for `deferred:parallel'. "
|
||||
(deferred:message "PARALLEL<KEY . VALUE>" )
|
||||
(let ((nd (deferred:new))
|
||||
(len (length alst))
|
||||
values)
|
||||
(cl-loop for pair in
|
||||
(deferred:parallel-func-to-deferred alst)
|
||||
with cd ; current child deferred
|
||||
do
|
||||
(let ((name (car pair)))
|
||||
(setq cd
|
||||
(deferred:nextc (cdr pair)
|
||||
(lambda (x)
|
||||
(push (cons name x) values)
|
||||
(deferred:message "PARALLEL VALUE [%s/%s] %s"
|
||||
(length values) len (cons name x))
|
||||
(when (= len (length values))
|
||||
(deferred:message "PARALLEL COLLECTED")
|
||||
(deferred:post-task nd 'ok (nreverse values)))
|
||||
nil)))
|
||||
(deferred:error cd
|
||||
(lambda (e)
|
||||
(push (cons name e) values)
|
||||
(deferred:message "PARALLEL ERROR [%s/%s] %s"
|
||||
(length values) len (cons name e))
|
||||
(when (= (length values) len)
|
||||
(deferred:message "PARALLEL COLLECTED")
|
||||
(deferred:post-task nd 'ok (nreverse values)))
|
||||
nil))))
|
||||
nd))
|
||||
|
||||
(defun deferred:parallel-list (lst)
|
||||
"[internal] Deferred list implementation for `deferred:parallel'. "
|
||||
(deferred:message "PARALLEL<LIST>" )
|
||||
(let* ((pd (deferred:parallel-main (deferred:parallel-array-to-alist lst)))
|
||||
(rd (deferred:nextc pd 'deferred:parallel-alist-to-array)))
|
||||
(setf (deferred-cancel rd)
|
||||
(lambda (x) (deferred:default-cancel x)
|
||||
(deferred:cancel pd)))
|
||||
rd))
|
||||
|
||||
(defun deferred:parallel (&rest args)
|
||||
"Return a deferred object that calls given deferred objects or
|
||||
functions in parallel and wait for all callbacks. The following
|
||||
deferred task will be called with an array of the return
|
||||
values. ARGS can be a list or an alist of deferred objects or
|
||||
functions."
|
||||
(deferred:message "PARALLEL : %s" args)
|
||||
(deferred:trans-multi-args args
|
||||
'deferred:parallel 'deferred:parallel-list 'deferred:parallel-main))
|
||||
|
||||
(defun deferred:earlier-main (alst)
|
||||
"[internal] Deferred alist implementation for `deferred:earlier'. "
|
||||
(deferred:message "EARLIER<KEY . VALUE>" )
|
||||
(let ((nd (deferred:new))
|
||||
(len (length alst))
|
||||
value results)
|
||||
(cl-loop for pair in
|
||||
(deferred:parallel-func-to-deferred alst)
|
||||
with cd ; current child deferred
|
||||
do
|
||||
(let ((name (car pair)))
|
||||
(setq cd
|
||||
(deferred:nextc (cdr pair)
|
||||
(lambda (x)
|
||||
(push (cons name x) results)
|
||||
(cond
|
||||
((null value)
|
||||
(setq value (cons name x))
|
||||
(deferred:message "EARLIER VALUE %s" (cons name value))
|
||||
(deferred:post-task nd 'ok value))
|
||||
(t
|
||||
(deferred:message "EARLIER MISS [%s/%s] %s" (length results) len (cons name value))
|
||||
(when (eql (length results) len)
|
||||
(deferred:message "EARLIER COLLECTED"))))
|
||||
nil)))
|
||||
(deferred:error cd
|
||||
(lambda (e)
|
||||
(push (cons name e) results)
|
||||
(deferred:message "EARLIER ERROR [%s/%s] %s" (length results) len (cons name e))
|
||||
(when (and (eql (length results) len) (null value))
|
||||
(deferred:message "EARLIER FAILED")
|
||||
(deferred:post-task nd 'ok nil))
|
||||
nil))))
|
||||
nd))
|
||||
|
||||
(defun deferred:earlier-list (lst)
|
||||
"[internal] Deferred list implementation for `deferred:earlier'. "
|
||||
(deferred:message "EARLIER<LIST>" )
|
||||
(let* ((pd (deferred:earlier-main (deferred:parallel-array-to-alist lst)))
|
||||
(rd (deferred:nextc pd (lambda (x) (cdr x)))))
|
||||
(setf (deferred-cancel rd)
|
||||
(lambda (x) (deferred:default-cancel x)
|
||||
(deferred:cancel pd)))
|
||||
rd))
|
||||
|
||||
|
||||
(defun deferred:earlier (&rest args)
|
||||
"Return a deferred object that calls given deferred objects or
|
||||
functions in parallel and wait for the first callback. The
|
||||
following deferred task will be called with the first return
|
||||
value. ARGS can be a list or an alist of deferred objects or
|
||||
functions."
|
||||
(deferred:message "EARLIER : %s" args)
|
||||
(deferred:trans-multi-args args
|
||||
'deferred:earlier 'deferred:earlier-list 'deferred:earlier-main))
|
||||
|
||||
(defmacro deferred:timeout (timeout-msec timeout-form d)
|
||||
"Time out macro on a deferred task D. If the deferred task D
|
||||
does not complete within TIMEOUT-MSEC, this macro cancels the
|
||||
deferred task and return the TIMEOUT-FORM."
|
||||
`(deferred:earlier
|
||||
(deferred:nextc (deferred:wait ,timeout-msec)
|
||||
(lambda (x) ,timeout-form))
|
||||
,d))
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Application functions
|
||||
|
||||
(defvar deferred:uid 0 "[internal] Sequence number for some utilities. See the function `deferred:uid'.")
|
||||
|
||||
(defun deferred:uid ()
|
||||
"[internal] Generate a sequence number."
|
||||
(cl-incf deferred:uid))
|
||||
|
||||
(defun deferred:buffer-string (strformat buf)
|
||||
"[internal] Return a string in the buffer with the given format."
|
||||
(format strformat
|
||||
(with-current-buffer buf (buffer-string))))
|
||||
|
||||
(defun deferred:process (command &rest args)
|
||||
"A deferred wrapper of `start-process'. Return a deferred
|
||||
object. The process name and buffer name of the argument of the
|
||||
`start-process' are generated by this function automatically.
|
||||
The next deferred object receives stdout and stderr string from
|
||||
the command process."
|
||||
(deferred:process-gen 'start-process command args))
|
||||
|
||||
(defun deferred:process-shell (command &rest args)
|
||||
"A deferred wrapper of `start-process-shell-command'. Return a deferred
|
||||
object. The process name and buffer name of the argument of the
|
||||
`start-process-shell-command' are generated by this function automatically.
|
||||
The next deferred object receives stdout and stderr string from
|
||||
the command process."
|
||||
(deferred:process-gen 'start-process-shell-command command args))
|
||||
|
||||
(defun deferred:process-buffer (command &rest args)
|
||||
"A deferred wrapper of `start-process'. Return a deferred
|
||||
object. The process name and buffer name of the argument of the
|
||||
`start-process' are generated by this function automatically.
|
||||
The next deferred object receives stdout and stderr buffer from
|
||||
the command process."
|
||||
(deferred:process-buffer-gen 'start-process command args))
|
||||
|
||||
(defun deferred:process-shell-buffer (command &rest args)
|
||||
"A deferred wrapper of `start-process-shell-command'. Return a deferred
|
||||
object. The process name and buffer name of the argument of the
|
||||
`start-process-shell-command' are generated by this function automatically.
|
||||
The next deferred object receives stdout and stderr buffer from
|
||||
the command process."
|
||||
(deferred:process-buffer-gen 'start-process-shell-command command args))
|
||||
|
||||
(defun deferred:process-gen (f command args)
|
||||
"[internal]"
|
||||
(let ((pd (deferred:process-buffer-gen f command args)) d)
|
||||
(setq d (deferred:nextc pd
|
||||
(lambda (buf)
|
||||
(prog1
|
||||
(with-current-buffer buf (buffer-string))
|
||||
(kill-buffer buf)))))
|
||||
(setf (deferred-cancel d)
|
||||
(lambda (_x)
|
||||
(deferred:default-cancel d)
|
||||
(deferred:default-cancel pd)))
|
||||
d))
|
||||
|
||||
(defun deferred:process-buffer-gen (f command args)
|
||||
"[internal]"
|
||||
(let ((d (deferred:next)) (uid (deferred:uid)))
|
||||
(let ((proc-name (format "*deferred:*%s*:%s" command uid))
|
||||
(buf-name (format " *deferred:*%s*:%s" command uid))
|
||||
(pwd default-directory)
|
||||
(env process-environment)
|
||||
(con-type process-connection-type)
|
||||
(nd (deferred:new)) proc-buf proc)
|
||||
(deferred:nextc d
|
||||
(lambda (_x)
|
||||
(setq proc-buf (get-buffer-create buf-name))
|
||||
(condition-case err
|
||||
(let ((default-directory pwd)
|
||||
(process-environment env)
|
||||
(process-connection-type con-type))
|
||||
(setq proc
|
||||
(if (null (car args))
|
||||
(apply f proc-name buf-name command nil)
|
||||
(apply f proc-name buf-name command args)))
|
||||
(set-process-sentinel
|
||||
proc
|
||||
(lambda (proc event)
|
||||
(unless (process-live-p proc)
|
||||
(if (zerop (process-exit-status proc))
|
||||
(deferred:post-task nd 'ok proc-buf)
|
||||
(let ((msg (format "Deferred process exited abnormally:\n command: %s\n exit status: %s %s\n event: %s\n buffer contents: %S"
|
||||
command
|
||||
(process-status proc)
|
||||
(process-exit-status proc)
|
||||
(string-trim-right event)
|
||||
(if (buffer-live-p proc-buf)
|
||||
(with-current-buffer proc-buf
|
||||
(buffer-string))
|
||||
"(unavailable)"))))
|
||||
(kill-buffer proc-buf)
|
||||
(deferred:post-task nd 'ng msg))))))
|
||||
(setf (deferred-cancel nd)
|
||||
(lambda (x) (deferred:default-cancel x)
|
||||
(when proc
|
||||
(kill-process proc)
|
||||
(kill-buffer proc-buf)))))
|
||||
(error (deferred:post-task nd 'ng err)))
|
||||
nil))
|
||||
nd)))
|
||||
|
||||
(defmacro deferred:processc (d command &rest args)
|
||||
"Process chain of `deferred:process'."
|
||||
`(deferred:nextc ,d
|
||||
(lambda (,(cl-gensym)) (deferred:process ,command ,@args))))
|
||||
|
||||
(defmacro deferred:process-bufferc (d command &rest args)
|
||||
"Process chain of `deferred:process-buffer'."
|
||||
`(deferred:nextc ,d
|
||||
(lambda (,(cl-gensym)) (deferred:process-buffer ,command ,@args))))
|
||||
|
||||
(defmacro deferred:process-shellc (d command &rest args)
|
||||
"Process chain of `deferred:process'."
|
||||
`(deferred:nextc ,d
|
||||
(lambda (,(cl-gensym)) (deferred:process-shell ,command ,@args))))
|
||||
|
||||
(defmacro deferred:process-shell-bufferc (d command &rest args)
|
||||
"Process chain of `deferred:process-buffer'."
|
||||
`(deferred:nextc ,d
|
||||
(lambda (,(cl-gensym)) (deferred:process-shell-buffer ,command ,@args))))
|
||||
|
||||
;; Special variables defined in url-vars.el.
|
||||
(defvar url-request-data)
|
||||
(defvar url-request-method)
|
||||
(defvar url-request-extra-headers)
|
||||
|
||||
(declare-function url-http-symbol-value-in-buffer "url-http"
|
||||
(symbol buffer &optional unbound-value))
|
||||
|
||||
(declare-function deferred:url-param-serialize "request" (params))
|
||||
|
||||
(declare-function deferred:url-escape "request" (val))
|
||||
|
||||
(eval-after-load "url"
|
||||
;; for url package
|
||||
;; TODO: proxy, charaset
|
||||
;; List of gloabl variables to preserve and restore before url-retrieve call
|
||||
'(let ((url-global-variables '(url-request-data
|
||||
url-request-method
|
||||
url-request-extra-headers)))
|
||||
|
||||
(defun deferred:url-retrieve (url &optional cbargs silent inhibit-cookies)
|
||||
"A wrapper function for url-retrieve. The next deferred
|
||||
object receives the buffer object that URL will load
|
||||
into. Values of dynamically bound 'url-request-data', 'url-request-method' and
|
||||
'url-request-extra-headers' are passed to url-retrieve call."
|
||||
(let ((nd (deferred:new))
|
||||
buf
|
||||
(local-values (mapcar (lambda (symbol) (symbol-value symbol)) url-global-variables)))
|
||||
(deferred:next
|
||||
(lambda (_x)
|
||||
(cl-progv url-global-variables local-values
|
||||
(condition-case err
|
||||
(setq buf
|
||||
(url-retrieve
|
||||
url (lambda (_xx) (deferred:post-task nd 'ok buf))
|
||||
cbargs silent inhibit-cookies))
|
||||
(error (deferred:post-task nd 'ng err)))
|
||||
nil)))
|
||||
(setf (deferred-cancel nd)
|
||||
(lambda (_x)
|
||||
(when (buffer-live-p buf)
|
||||
(kill-buffer buf))))
|
||||
nd))
|
||||
|
||||
(defun deferred:url-delete-header (buf)
|
||||
(with-current-buffer buf
|
||||
(let ((pos (url-http-symbol-value-in-buffer
|
||||
'url-http-end-of-headers buf)))
|
||||
(when pos
|
||||
(delete-region (point-min) (1+ pos)))))
|
||||
buf)
|
||||
|
||||
(defun deferred:url-delete-buffer (buf)
|
||||
(when (and buf (buffer-live-p buf))
|
||||
(kill-buffer buf))
|
||||
nil)
|
||||
|
||||
(defun deferred:url-get (url &optional params &rest args)
|
||||
"Perform a HTTP GET method with `url-retrieve'. PARAMS is
|
||||
a parameter list of (key . value) or key. ARGS will be appended
|
||||
to deferred:url-retrieve args list. The next deferred
|
||||
object receives the buffer object that URL will load into."
|
||||
(when params
|
||||
(setq url
|
||||
(concat url "?" (deferred:url-param-serialize params))))
|
||||
(let ((d (deferred:$
|
||||
(apply 'deferred:url-retrieve url args)
|
||||
(deferred:nextc it 'deferred:url-delete-header))))
|
||||
(deferred:set-next
|
||||
d (deferred:new 'deferred:url-delete-buffer))
|
||||
d))
|
||||
|
||||
(defun deferred:url-post (url &optional params &rest args)
|
||||
"Perform a HTTP POST method with `url-retrieve'. PARAMS is
|
||||
a parameter list of (key . value) or key. ARGS will be appended
|
||||
to deferred:url-retrieve args list. The next deferred
|
||||
object receives the buffer object that URL will load into."
|
||||
(let ((url-request-method "POST")
|
||||
(url-request-extra-headers
|
||||
(append url-request-extra-headers
|
||||
'(("Content-Type" . "application/x-www-form-urlencoded"))))
|
||||
(url-request-data (deferred:url-param-serialize params)))
|
||||
(let ((d (deferred:$
|
||||
(apply 'deferred:url-retrieve url args)
|
||||
(deferred:nextc it 'deferred:url-delete-header))))
|
||||
(deferred:set-next
|
||||
d (deferred:new 'deferred:url-delete-buffer))
|
||||
d)))
|
||||
|
||||
(defun deferred:url-escape (val)
|
||||
"[internal] Return a new string that is VAL URI-encoded."
|
||||
(unless (stringp val)
|
||||
(setq val (format "%s" val)))
|
||||
(url-hexify-string
|
||||
(encode-coding-string val 'utf-8)))
|
||||
|
||||
(defun deferred:url-param-serialize (params)
|
||||
"[internal] Serialize a list of (key . value) cons cells
|
||||
into a query string."
|
||||
(when params
|
||||
(mapconcat
|
||||
'identity
|
||||
(cl-loop for p in params
|
||||
collect
|
||||
(cond
|
||||
((consp p)
|
||||
(concat
|
||||
(deferred:url-escape (car p)) "="
|
||||
(deferred:url-escape (cdr p))))
|
||||
(t
|
||||
(deferred:url-escape p))))
|
||||
"&")))
|
||||
))
|
||||
|
||||
|
||||
(provide 'deferred)
|
||||
;;; deferred.el ends here
|
Binary file not shown.
|
@ -0,0 +1,612 @@
|
|||
New in Elpy 1.24.0
|
||||
==================
|
||||
|
||||
- Eldoc messages are a bit nicer now
|
||||
- Flymake has a useful modeline in Emacs 26 now, so Elpy won't hide it
|
||||
anymore
|
||||
- Elpy will now also use the Python shell to suggest completions
|
||||
|
||||
New in Elpy 1.23.0
|
||||
==================
|
||||
|
||||
- Use the new ``elpy-syntax-check-command`` variable to configure
|
||||
which syntax checker to use in Emacs 26
|
||||
- Sending a "group" to the shell now uses the ``o`` suffix instead of
|
||||
``g`` to avoid clashing with ``C-g``
|
||||
|
||||
New in Elpy 1.22.0
|
||||
==================
|
||||
|
||||
- Elpy now supports the Black source code formatter.
|
||||
- Make Elpy work more nicely with the new Flymake.
|
||||
- Support Emacs 26.1
|
||||
- Lots of bugfixes.
|
||||
|
||||
New in Elpy 1.21.0
|
||||
==================
|
||||
|
||||
- Debian now ships with elpy, you can use apt-get to install it.
|
||||
- Elpy now knows how to deal with the flymake in the upcoming Emacs
|
||||
release.
|
||||
- Some minor improvements in error messages and warnings.
|
||||
|
||||
New in Elpy 1.20.0
|
||||
==================
|
||||
|
||||
- No new features, but lots of bugfixes
|
||||
|
||||
Thanks again to Gaby Launay for the continued and exceptional work!
|
||||
|
||||
|
||||
New in Elpy 1.19.0
|
||||
==================
|
||||
|
||||
- Python 3.6 and Emacs 25.3 are now officially supported.
|
||||
- Sending code to a Python process is now a lot more convenient, see
|
||||
the documentation for more information.
|
||||
- Elpy can now automatically update the buffer displaying help for the
|
||||
symbol under point. Customize ``elpy-modules`` and enable the autodoc
|
||||
module there!
|
||||
- yapf and autopep8 now use their respective config files in the
|
||||
project root.
|
||||
- And tons of bugfixes.
|
||||
|
||||
Thanks to Craig MacEachern, Daniel Gopar, Gaby Launay, Maxim
|
||||
Cournoyer, Nicholas D. Steeves and Sam Steingold for their help in
|
||||
making this release!
|
||||
|
||||
|
||||
New in Elpy 1.18.0
|
||||
==================
|
||||
|
||||
- Elpy is now using MELPA Stable as the official distribution point.
|
||||
Please remove jorgenschaefer.github.io from your sources list if you
|
||||
still use it. It will not receive further updates after 1.18.
|
||||
- New commands for interacting with the Python shell, thanks to Rainer
|
||||
Gemulla. Check them out at
|
||||
https://elpy.readthedocs.io/en/latest/ide.html#evaluating-code-fragments
|
||||
- Shells started using ``C-c C-z`` will now use the project root as
|
||||
the current directory, to be in line with other code sending
|
||||
functionality.
|
||||
- importmagic has been removed. While this package added some nice
|
||||
functionality to Elpy, the way it worked by importing every module
|
||||
caused a lot of bugs. It was not an easy decision, but this is
|
||||
better for most Elpy users.
|
||||
- Rope is no longer supported for completions and similar
|
||||
functionality. Refactoring support using Rope is still there. Sadly,
|
||||
Rope has not received much of any update in a long time, and
|
||||
attempts to revive it failed. Maintaining multiple code paths to
|
||||
support both Jedi and Rope was complicated, so we decided to get rid
|
||||
of Rope for these features. Jedi is almost always an equivalent if
|
||||
not better choice.
|
||||
- The Green test runner is now supported by default.
|
||||
- Beyond all of this, there were numerous bugfixes.
|
||||
|
||||
We are happy to report that Elpy now has more maintainers! Daniel
|
||||
Gopar, Rainer Gemulla and @galaunay are now helping regularly with
|
||||
this project.
|
||||
|
||||
Thanks to all the contributors!
|
||||
|
||||
|
||||
New in Elpy 1.17.0
|
||||
==================
|
||||
|
||||
- The xref functionality in newer Emacsen is now supported for
|
||||
following symbols at point.
|
||||
- Elpy now supports PEP 397 for Windows executable names.
|
||||
- In addition to pylint, Elpy now also supports epylint correctly.
|
||||
- A number of features for working with interactive Python have been added to
|
||||
Elpy; e.g., commands for sending code fragments to the Python shell and the
|
||||
ability to echo their output in the message area. See the documentation for a
|
||||
full list.
|
||||
- Bunch of little bugfixes.
|
||||
|
||||
|
||||
New in Elpy 1.16.0
|
||||
==================
|
||||
|
||||
- You can now change which function is used to run test commands,
|
||||
instead of the default ``compile``, using
|
||||
``elpy-test-compilation-function``. This allows using ``pdb`` to run
|
||||
tests in a debugger, for example.
|
||||
- Elpy now sets ``IPY_TEST_SIMPLE_PROMPT``, which should prevent a
|
||||
number of problems with IPython 5.
|
||||
- If you like Elpy, you can now sponsor its development using Patreon
|
||||
at https://www.patreon.com/jorgenschaefer
|
||||
|
||||
|
||||
New in Elpy 1.15.0
|
||||
==================
|
||||
|
||||
- Elpy now supports profiling, try ``elpy-profile-buffer-or-region``!
|
||||
- Do not randomly downcase completion candidates anymore.
|
||||
- Work around a bug in Emacs 25.1 and before related to current
|
||||
IPython shells.
|
||||
- And lots of other bugfixes.
|
||||
|
||||
|
||||
New in Elpy 1.14.0
|
||||
==================
|
||||
|
||||
- Basic Django support. Try ``C-c C-x c`` and ``C-c C-x r``! Thanks to
|
||||
Daniel Gopar for this.
|
||||
- You can now use manage.py to run Django tests, instead of always
|
||||
using django-admin.py.
|
||||
- When called with a prefix argument ``elpy-importmagic-add-import``
|
||||
will now ask for an alias name to import as.
|
||||
|
||||
|
||||
New in Elpy 1.13.0
|
||||
==================
|
||||
|
||||
- Fewer surprises with syntax checks, ``C-c C-z``, reformatting
|
||||
- Improved behavior for reformatting.
|
||||
- Improved documentation for IPython. IPython 5 broke a lot of things
|
||||
with Emacs. Use it at your own risk.
|
||||
|
||||
|
||||
New in Elpy 1.12.0
|
||||
==================
|
||||
|
||||
- Some symbols can now be completed with parentheses after them,
|
||||
useful for functions. The heuristic for when to add parentheses and
|
||||
not is not optimal, so this is not enabled by default—customize
|
||||
``elpy-company-post-completion-function`` to enable this feature.
|
||||
- Support dedicated Python shells (one per Python file). You can
|
||||
customized ``elpy-dedicated-shells`` to make this the default.
|
||||
- Elpy now uses ``python -m pip`` instead of pip directly to improve
|
||||
interaction with virtualenvs.
|
||||
- Support for Python 2.6 has been officially dropped.
|
||||
- Display for backend errors has been disabled by default. Jedi has
|
||||
not had a release in a long while, and many bugs have been unfixed.
|
||||
These errors have only caused added workload for Elpy maintainers.
|
||||
The option will be reverted once Jedi has had a new release.
|
||||
|
||||
|
||||
New in Elpy 1.11.0
|
||||
==================
|
||||
|
||||
- Elpy now supports yapf to format your code.
|
||||
- You can now adjust whether Elpy should hide modes from the mode line
|
||||
or not using ``elpy-remove-modeline-lighter``
|
||||
- When the new option ``elpy-disable-backend-error-display`` is set,
|
||||
Elpy will not show its error pop-up anymore. This can be useful if
|
||||
you run into an annoying bug in Jedi, for example.
|
||||
- New command ``elpy-goto-definition-other-window`` on ``C-x 4 M-.``.
|
||||
- Expanding ``super`` now gives the short form supported in Python 3.
|
||||
- All Rope errors are now caught, as the upstream maintainers did not
|
||||
show interest in distinguishing between malformed input and bugs in
|
||||
their library.
|
||||
|
||||
|
||||
New in Elpy 1.10.0
|
||||
==================
|
||||
|
||||
- Marking the current indentation level at the top level will now mark
|
||||
the whole buffer.
|
||||
- The region will be normalized before re-indenting it, making the
|
||||
behavior more predictable for partially marked lines.
|
||||
- Using autopep8 on the whole buffer will now keep point (roughly) at
|
||||
the same location as it was.
|
||||
- The autopep8 code now also uses the same configuration options as
|
||||
the command line tool.
|
||||
- Malformed JSON data from the backend is now handled better.
|
||||
- RPC processes are restarted when the current virtualenv changes.
|
||||
- Python 3.5 is now officially supported.
|
||||
- Flymake will now not be enabled in buffers without file name, where
|
||||
it can't run anyhow, or when the checker program does not exist in
|
||||
the first place.
|
||||
- It is now possible to ask Elpy not to remove the mode line lighter
|
||||
of company mode, which can be useful if you use company in other
|
||||
modes.
|
||||
- Test discovery now also allows file names without "test" in them to
|
||||
be tested. Classes and methods still require the substring, though.
|
||||
- Spurious equals signs at the end of completions from Jedi will now
|
||||
be ignored.
|
||||
- Various other bug fixes.
|
||||
|
||||
|
||||
New in Elpy 1.9.0
|
||||
=================
|
||||
|
||||
- Elpy now supports the ``autopep8`` library for automatically
|
||||
formatting Python code. All refactoring-related code is now grouped
|
||||
under ``C-c C-r``. Use ``C-c C-r i`` to fix up imports using
|
||||
importmagic, ``C-c C-r p`` to fix up Python code with autopep8, and
|
||||
``C-c C-r r`` to bring up the old Rope refactoring menu.
|
||||
- ``C-c C-b`` will now select a region containing surrounding lines of
|
||||
the current indentation or more.
|
||||
- ``C-c C-z`` in a Python shell will now switch back to the last
|
||||
Python buffer, allowing to use the key to cycle back and forth
|
||||
between the Python buffer and shell.
|
||||
- The pattern used for ``C-c C-s`` is now customizeable in
|
||||
``elpy-rgrep-file-pattern``.
|
||||
- ``<C-return>`` now can be used to send the current statement to the
|
||||
Python shell. Be careful, this can break with nested statements.
|
||||
- The Elpy minor mode now also works in modes derived from
|
||||
``python-mode``, not just in the mode itself.
|
||||
|
||||
|
||||
New in Elpy 1.8.1
|
||||
=================
|
||||
|
||||
- Ignore a ``KeyError`` from Jedi 0.9.0 which occurs a lot in normal
|
||||
code.
|
||||
|
||||
|
||||
New in Elpy 1.8.0
|
||||
=================
|
||||
|
||||
- Emacs 24.5 is now officially supported
|
||||
- The new configuration option ``elpy-rpc-ignored-buffer-size`` defines a maximum buffer size to be handle completion in, to avoid laggy interaction in unusually large files
|
||||
- Indentation block movement was replaced with code that just moves the marked block or the current line; this should be a lot less magical and more predictable
|
||||
- Running the test at point now correctly ignores any inner methods
|
||||
- Jedi docstrings now show the full name of the object
|
||||
- The RPC interpreter is now chosen correctly on cygwin
|
||||
- ``elpy-shell-send-region-or-buffer`` now warns of tabs in the data being sent
|
||||
- Elpy now binds stdout and stderr to ``/dev/null`` to avoid being confused by spurious output from other libraries
|
||||
- RPC buffers (and processes) are removed after some time to avoid them piling up endlessly
|
||||
- It is not possibly anymore to use customize alone to use ipython, because of some bad interaction between custom options in Elpy and python.el
|
||||
- And lots of bugfixes (50 issues closed!)
|
||||
|
||||
|
||||
New in Elpy 1.7.1
|
||||
=================
|
||||
|
||||
- Do not fail on errors from importmagic.
|
||||
- Handle new minor mode behavior of new versions of yasnippet.
|
||||
- Do use the argument to ``elpy-use-ipython`` correctly.
|
||||
- Handle unexpected data from the backend more gracefully.
|
||||
|
||||
|
||||
New in Elpy 1.7.0
|
||||
=================
|
||||
|
||||
- Elpy now can add missing import directives automatically, by using
|
||||
Alec Thomas' excellent importmagic_ library. Use ``C-c C-m`` to add
|
||||
a single import statement, or ``C-c C-S-m`` to include all missing
|
||||
import statements. Many thanks to Georg Brandl for doing a lot of
|
||||
work to bring this feature to Elpy!
|
||||
- The Jedi backend now also supports ``C-c C-d`` to display a
|
||||
docstring. Thanks again to Georg Brandl for the patch.
|
||||
- It is now possible to disable the display of the current function in
|
||||
the echo area by setting ``elpy-eldoc-show-current-function`` to
|
||||
``nil``.
|
||||
- idomenu was removed.
|
||||
- Twisted's Trial test runner is now supported. Thanks to Elric Milon
|
||||
for the patch!
|
||||
- All test runners now use a variable to decide which command to run,
|
||||
which for example allows using ``manage.py`` for the Django test
|
||||
runner, or your own test script which sets up the environment
|
||||
correctly.
|
||||
- Emacs 24.4 is now officially supported.
|
||||
- Various bugfixes.
|
||||
|
||||
.. _importmagic: https://github.com/alecthomas/importmagic
|
||||
|
||||
New in Elpy 1.6.0
|
||||
=================
|
||||
|
||||
- When point is on a line with a flymake error, Elpy will now show the
|
||||
error in the echo area.
|
||||
- The movement commands (``C-<cursor>``) have been reworked again.
|
||||
Going left and right will now move by indentation levels left of the
|
||||
current indentation, i.e. jump four spaces, and by words right of
|
||||
the current indentation. Going up and down will go to the previous
|
||||
or next line with the indentation level point is at, not the
|
||||
indentation the line has. Try it, it's more difficult to explain
|
||||
than to use.
|
||||
- Completion results are now sorted more sensibly, with
|
||||
single-underscore symbols at the end, and double-underscore symbols
|
||||
after normal symbols, but before single-underscore ones.
|
||||
- ``M-x elpy-config`` will now point out if there are newer versions
|
||||
available for packages used by Elpy.
|
||||
- ``M-x elpy-config`` will now warn if ``~/.local/bin`` is not in
|
||||
``PATH`` while there is no virtualenv active.
|
||||
- The ``M-x elpy-version`` command is back by popular demand.
|
||||
- RPC buffers used by Elpy are now hidden by default, having a space
|
||||
at the beginning of the name.
|
||||
- When the Rope library throws an error, Elpy will now also attempt to
|
||||
provide reproduction steps. This used to only happen for Jedi.
|
||||
- Various bug fixes.
|
||||
|
||||
|
||||
New in Elpy 1.5.1
|
||||
=================
|
||||
|
||||
- Fix a bug where company-mode might get confused about the current
|
||||
backend, leading to an error about ``Symbol's function definition is
|
||||
void: nil``
|
||||
- Fix Rope so it won’t search the whole project directory. This was an
|
||||
intended feature in v1.5 which did not work originally.
|
||||
- Use ``yas-text`` instead of ``text`` in snippets for compatibility
|
||||
with the unreleased yasnippet from MELPA (thanks to Daniel Wu!)
|
||||
|
||||
New in Elpy 1.5.0
|
||||
=================
|
||||
|
||||
- Elpy now has a `manual`_. Additionally, there's a menu bar now which
|
||||
should make it easier to discover Elpy features.
|
||||
- The Elpy Python package now ships with the Emacs Lisp package,
|
||||
removing the need to install Elpy via pip.
|
||||
- Python 3.4 is now officially supported.
|
||||
- The new command ``elpy-config`` can be used to configure Elpy using
|
||||
Emacs' built-in customize system. Elpy has been changed to make the
|
||||
most of this.
|
||||
- Elpy now uses company-mode instead of auto-complete for on-the-fly
|
||||
auto completion. This changes a few things. There is no automatic
|
||||
documentation popup anymore. Instead, you can type ``C-d`` and get
|
||||
the documentation buffer. In addition, you can type ``C-w`` to see
|
||||
the source of the current candidate in context.
|
||||
- Elpy now uses pyvenv as the virtualenv module, enabling
|
||||
virtualenvwrapper hooks.
|
||||
- We now ship with a large number of YASnippet snippets. Try ``M-x
|
||||
yas-insert-snippet``.
|
||||
- The new unified test running interface on ``C-c C-t`` will try to
|
||||
determine the current test and run it, or, failing that, run all
|
||||
tests. Provide a prefix argument to just run all tests no matter
|
||||
what. You can change the test runner to be used using
|
||||
``elpy-set-test-runner``. Elpy supports the default unittest
|
||||
discover runner, the Django discover runner, nosetests and py.test
|
||||
by default. New test runners can easily be defined.
|
||||
- There's a new multi-edit functionality. ``C-c C-e`` will edit all
|
||||
occurrences of the symbol under point. When using Jedi, this is
|
||||
using semantic information as opposed to just syntactic one. When a
|
||||
region is active, edit all occurrences of the text in region in the
|
||||
current buffer.
|
||||
- When sending Python code to the interactive interpreter using ``C-c
|
||||
C-c``, Elpy will now not automatically pop to the interpreter
|
||||
anymore. Use ``C-c C-z`` to switch to the interpreter.
|
||||
- Elpy will now display the current class and function if there is no
|
||||
call tip to be displayed. Removes the ``C-c C-q`` binding.
|
||||
- If there is a call tip, highlight the current argument (requires Jedi).
|
||||
- The documentation interface using ``C-c C-d`` is much smarter now,
|
||||
falling back to pydoc when necessary and providing sensible
|
||||
completion for that, too. Provide a prefix argument if you want no
|
||||
smarts, just pydoc.
|
||||
- ``<S-return>`` and ``<C-S-return>`` now open a line below or above
|
||||
the current one.
|
||||
- ``<C-cursor>`` will now navigate between Python blocks of the same
|
||||
indentation level. ``<M-cursor>`` will move the current block. Try
|
||||
it, it's easier to understand when you see it than to explain it.
|
||||
- There's a new concept of modules. The variable
|
||||
``elpy-default-minor-modes`` is gone (use ``elpy-mode-hook`` for
|
||||
minor modes). Instead, there's now ``elpy-modules`` which can be
|
||||
used to enable or disable certain features of Elpy.
|
||||
- ``elpy-clean-modeline`` is gone, modules now clean themselves up.
|
||||
- Elpy now distinguishes between the project root, where project files
|
||||
are located, and the library root, which should be part of
|
||||
``sys.path`` to import the module under development.
|
||||
- ``elpy-project-ignored-directories`` replaces the old
|
||||
``elpy-rgrep-ignored-directories`` and is used by more features.
|
||||
- ``elpy-doc-websearch`` has been removed as it was barely useable
|
||||
as is.
|
||||
- Elpy now tries to be more helpful when errors in the backend happen.
|
||||
This removes ``elpy-rpc-traceback``, as that will be displayed by
|
||||
default.
|
||||
- Optimizations were added to handle large files, making general
|
||||
interaction a lot faster.
|
||||
- When Rope is being used, do not search through unusually large
|
||||
directories. This should speed up interaction in those cases,
|
||||
especially when editing a file in the home directory.
|
||||
- And a whole lot of minor bug fixes and little improvements.
|
||||
|
||||
.. _manual: https://elpy.readthedocs.io/
|
||||
|
||||
|
||||
New in Elpy 1.4.2
|
||||
==================
|
||||
|
||||
- Minor bugfix to prevent an error from projectile-project-root to
|
||||
interfere with Elpy’s project finding strategy.
|
||||
|
||||
New in Elpy 1.4.1
|
||||
=================
|
||||
|
||||
- Elpy now sets project-wide preferences for Rope, enabling completion
|
||||
in the sys package, among others.
|
||||
- An error is avoided in the Jedi backend when trying to go to symbols
|
||||
in compiled packages.
|
||||
- A compatibility alias was added for nose.el, which insists on
|
||||
breaking backwards compatibility with Emacs 24.x.
|
||||
|
||||
New in Elpy 1.4.0
|
||||
=================
|
||||
|
||||
- Elpy has moved to its own ELPA. Make sure to update your
|
||||
package-archives (as described above).
|
||||
- For a file in a Projectile-managed project is opened, Elpy will now
|
||||
use Projectile’s project root.
|
||||
- When the user has set a valid python-check-command, elpy will now
|
||||
refrain from overriding it.
|
||||
- On Windows, elpy is now using the pythonw.exe interpreter for the
|
||||
RPC process, as that seems to be causing fewer issues.
|
||||
- And various smaller bugfixes.
|
||||
|
||||
New in Elpy 1.3.0
|
||||
=================
|
||||
|
||||
- virtualenv.el has been replaced by pyvenv.el, as that library offers
|
||||
more features.
|
||||
- elpy-rpc-restart now works globally, not just in Elpy buffers.
|
||||
- Elpy does not try to complete in comments anymore.
|
||||
- The new command elpy-rpc-traceback gives access to the last stack
|
||||
trace in the Elpy backend, helping with debugging problems.
|
||||
- The flymake check function is now run with the current directory as
|
||||
/ to avoid accidental imports.
|
||||
- Ensure correct handling of yas-snippet-dirs by Elpy. This variable
|
||||
can be a string, so ensure it’s a list before adding to it.
|
||||
- The new variable elpy-show-installation-instructions can be used to
|
||||
disable the installation screen.
|
||||
- Fix a very nasty bug causing spurious empty lines in a buffer or
|
||||
consume 100% CPU in certain situations when using the Jedi backend.
|
||||
Thanks to Matthias Dahl for finding this bug.
|
||||
- Various other bugfixes.
|
||||
|
||||
New in Elpy 1.2.1
|
||||
=================
|
||||
|
||||
Bugfix release.
|
||||
|
||||
- The refactoring was not ported to the new asynchronous API,
|
||||
resulting in an error when refactoring was attempted.
|
||||
- The project root now always returns a directory. Too many parts of
|
||||
elpy relies on this. If the project root turns out to be your home
|
||||
directory, elpy will warn you about it.
|
||||
- Elpy now works correctly with Emacs 24.2. There were some
|
||||
compatibility functions missing.
|
||||
- Blocking RPC calls now do not block for one second even if there is
|
||||
process output.
|
||||
|
||||
New in Elpy 1.2
|
||||
===============
|
||||
|
||||
- Elpy now uses asynchronous RPC. This means that Emacs should not
|
||||
freeze anymore while eldoc or auto-complete functions run.
|
||||
- ``elpy-shell-send-region-or-buffer`` will now remove common
|
||||
indentation of the region, making it possible to easily send parts
|
||||
of an if statement or function body without manually adjusting the
|
||||
indentation.
|
||||
- The Python package depends on ``flake8``, and will also try to be
|
||||
smarter when detecting ``flake8`` for on-the-fly checking.
|
||||
- ``elpy-check`` can be run with a prefix argument to check the whole
|
||||
project, instead of only the current file.
|
||||
- ``elpy-rgrep-symbol`` now ignores a few common directories
|
||||
(``.tox``, ``build``, ``dist``).
|
||||
- When using the rope backend, Elpy will not create the
|
||||
``.ropeproject`` folders anymore. This should keep projects a lot
|
||||
cleaner.
|
||||
|
||||
New in Elpy 1.1
|
||||
===============
|
||||
|
||||
- Elpy now always uses the root directory of the package as the
|
||||
project root; this should avoid some confusion and improve
|
||||
auto-completion suggestions
|
||||
- ``elpy-shell-send-region-or-buffer`` now accepts a prefix argument
|
||||
to run code wrapped behind ``if __name__ == '__main__'``, which is
|
||||
ignored by default
|
||||
- ``elpy-project-root`` is now a safe local variable and can be set
|
||||
from file variables
|
||||
- Elpy now supports project-specific RPC processes, see
|
||||
``elpy-rpc-project-specific`` for how to use this
|
||||
- ``M-*`` now works to go back where you came from after a ``M-.``
|
||||
- Elpy now ships with a few dedicated snippets for YASnippet
|
||||
- Support and require Jedi 0.6.0
|
||||
|
||||
New in Elpy 1.0
|
||||
===============
|
||||
|
||||
- Version 0.9 was a release candidate, so this release focused on bug
|
||||
fixes instead of new features.
|
||||
- ``elpy-enable`` now takes an optional argument that skips variable
|
||||
initialization for those users who prefer their own defaults for
|
||||
other modes.
|
||||
- ``python-check.sh`` has been removed from Elpy, as the flake8 tool
|
||||
from pypi does everything it does, only better.
|
||||
- Elpy will now start the helper subprocess in the root directory,
|
||||
avoiding accidental Python path clobbering.
|
||||
|
||||
New in Elpy 0.9
|
||||
===============
|
||||
|
||||
- Elpy now officially support Python 2.6, 2.7 and 3.3 on Emacs 24.2
|
||||
and 24.3, with continuous integration tests thanks to
|
||||
`Travis CI`_.
|
||||
- Extended support for Pydoc. ``C-u C-c C-d`` will now prompt for an
|
||||
auto-completed symbol to run Pydoc on. The pydoc output will be
|
||||
formatted and placed in a help buffer for easy review.
|
||||
- Refactoring support is back. ``C-c C-r`` will pop up a refactoring
|
||||
wizard offering various refactoring options. Most of them depend on
|
||||
the presence of Rope, though, even if Jedi is used as a completion
|
||||
backend.
|
||||
- The Rope backend has been extended to provide completions for
|
||||
modules in an import clause.
|
||||
- New refactoring option: Add missing imports. This will search for
|
||||
undefined symbols in the current file and automatically add
|
||||
appropriate imports.
|
||||
- ``C-c C-c (elpy-rgrep-symbol)`` now prompts for a regexp when a prefix
|
||||
argument is given instead of using the symbol at point.
|
||||
|
||||
.. _Travis CI: https://travis-ci.org/
|
||||
|
||||
New in Elpy 0.8
|
||||
===============
|
||||
|
||||
Python Backend Rewrite
|
||||
----------------------
|
||||
|
||||
- Elpy does not use Pymacs, Ropemacs and Ropemode anymore, but instead
|
||||
provides its own Python interface with the elpy package on PyPI.
|
||||
- This not only should improve performance, but also enables using
|
||||
Jedi as an alternative backend for completion. Use ``M-x
|
||||
elpy-set-backend`` to change between rope and jedi. For now, this
|
||||
does disable all refactoring support, though.
|
||||
|
||||
Project Support
|
||||
---------------
|
||||
|
||||
- Elpy now has built-in project support. The interface is rather
|
||||
simple: You can set ``elpy-project-root`` to the correct value in
|
||||
``.dir-locals.el``, or just rely on the automatic detection. If you
|
||||
change your mind, you can always just ``elpy-set-project-root``.
|
||||
- New dependency: Find File in Project (ffip), bound to ``C-c C-f`` by
|
||||
default. This will allow you to find files anywhere in your project
|
||||
using a search-as-you-type interface like ido.
|
||||
- New dependency: nose, bound to ``C-c C-t`` by default. This will run
|
||||
the nosetests binary in the root of your current library directory.
|
||||
You can restrict the tests being run to the current test or the
|
||||
current module by adding prefix arguments.
|
||||
- New function: Recursive grep for symbol, bound to ``C-c C-s`` by
|
||||
default. This will search for the symbol at point in the whole
|
||||
project.
|
||||
|
||||
New dependencies
|
||||
----------------
|
||||
|
||||
- idomenu, bound to ``C-c C-j`` by default. This replaces the standard
|
||||
imenu interface with an ido-based search-as-you-type interface for
|
||||
definitions in the current buffer.
|
||||
- virtualenv.el, replacing pyvirtualenv.el). Use ``M-x
|
||||
virtualenv-workon`` to enable a virtualenv.
|
||||
- iedit.el, bound to ``M-,`` by default. This highlights all occurrences
|
||||
of the symbol at point or the active region in the current buffer or
|
||||
narrowing. When you edit any of them, all others will be edited the
|
||||
same. This allows some basic and very quick refactoring.
|
||||
- New variable ``elpy-default-minor-modes`` which is run by ``elpy-mode``
|
||||
on startup. If you don’t want to use some modes, remove them from
|
||||
here.
|
||||
|
||||
Key Bindings and Functions
|
||||
--------------------------
|
||||
|
||||
- The key bindings have been reworked and cleaned up. Sorry, this
|
||||
might cause confusion.
|
||||
- Yasnippet is now on its own keybinding, ``C-c C-i``, instead of
|
||||
sharing the auto-complete interface. This was done because some
|
||||
snippets conflicted with legitimate, unsnippy completions.
|
||||
- New function: Occur Definitions, bound to ``C-c C-o`` by default. This
|
||||
will run the standard occur command to show definitions (classes and
|
||||
functions) in your current buffer, giving you a very quick outline
|
||||
and the ability to jump to different definitions quickly.
|
||||
- New function: Show Defun, bound to ``C-c C-q`` by default. This will
|
||||
show the current method and possibly class in the mode line, which
|
||||
is helpful in long functions.
|
||||
- New functions: Forward/backward definition, bound to ``M-n`` and ``M-p``
|
||||
as well as ``<M-down>`` and ``<M-up>`` by default. These will jump to
|
||||
the next or previous definition (class or function), helping with
|
||||
quick navigation through a file.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
- The documentation function (``C-c C-d``) now uses pydoc when a prefix
|
||||
arg is given.
|
||||
- The web search function (``C-c C-w``) now searches for the current
|
||||
symbol by default. The tab-completing web documentation interface
|
||||
was removed and is scheduled to be replaced with a new pydoc
|
||||
interface in future versions.
|
||||
- The ``python-check.sh`` is now shipped with elpy. If you load elpy.el
|
||||
before you load python.el, it should be the default
|
||||
``python-check-command``.
|
|
@ -0,0 +1,84 @@
|
|||
;;; elpy-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'load-path (directory-file-name
|
||||
(or (file-name-directory #$) (car load-path))))
|
||||
|
||||
|
||||
;;;### (autoloads nil "elpy" "elpy.el" (0 0 0 0))
|
||||
;;; Generated autoloads from elpy.el
|
||||
|
||||
(autoload 'elpy-enable "elpy" "\
|
||||
Enable Elpy in all future Python buffers.
|
||||
|
||||
\(fn &optional IGNORED)" t nil)
|
||||
|
||||
(autoload 'elpy-mode "elpy" "\
|
||||
Minor mode in Python buffers for the Emacs Lisp Python Environment.
|
||||
|
||||
This mode fully supports virtualenvs. Once you switch a
|
||||
virtualenv using \\[pyvenv-workon], you can use
|
||||
\\[elpy-rpc-restart] to make the elpy Python process use your
|
||||
virtualenv.
|
||||
|
||||
\\{elpy-mode-map}
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'elpy-config "elpy" "\
|
||||
Configure Elpy.
|
||||
|
||||
This function will pop up a configuration buffer, which is mostly
|
||||
a customize buffer, but has some more options.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(autoload 'elpy-version "elpy" "\
|
||||
Display the version of Elpy.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "elpy" '("elpy-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "elpy-django" "elpy-django.el" (0 0 0 0))
|
||||
;;; Generated autoloads from elpy-django.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "elpy-django" '("elpy-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "elpy-profile" "elpy-profile.el" (0 0 0 0))
|
||||
;;; Generated autoloads from elpy-profile.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "elpy-profile" '("elpy-profile-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "elpy-refactor" "elpy-refactor.el" (0 0 0 0))
|
||||
;;; Generated autoloads from elpy-refactor.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "elpy-refactor" '("elpy-refactor")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "elpy-shell" "elpy-shell.el" (0 0 0 0))
|
||||
;;; Generated autoloads from elpy-shell.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "elpy-shell" '("elpy-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil nil ("elpy-pkg.el") (0 0 0 0))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
;;; elpy-autoloads.el ends here
|
|
@ -0,0 +1,260 @@
|
|||
;;; elpy-django.el --- Django extension for elpy
|
||||
|
||||
;; Copyright (C) 2013-2016 Jorgen Schaefer
|
||||
|
||||
;; Author: Daniel Gopar <gopardaniel@gmail.com>
|
||||
;; URL: https://github.com/jorgenschaefer/elpy
|
||||
|
||||
;; This program is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU General Public License
|
||||
;; as published by the Free Software Foundation; either version 3
|
||||
;; of the License, or (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file serves as an extension to elpy by adding django support
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 's)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; User customization
|
||||
|
||||
(defcustom elpy-django-command "django-admin.py"
|
||||
"Command to use when running Django specific commands.
|
||||
Best to set it to full path to 'manage.py' if it's available."
|
||||
:type 'string
|
||||
:safe 'stringp
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-command)
|
||||
|
||||
(defcustom elpy-django-server-ipaddr "127.0.0.1"
|
||||
"What address Django will use when running the dev server."
|
||||
:type 'string
|
||||
:safe 'stringp
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-server-ipaddr)
|
||||
|
||||
(defcustom elpy-django-server-port "8000"
|
||||
"What port Django will use when running the dev server."
|
||||
:type 'string
|
||||
:safe 'stringp
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-server-port)
|
||||
|
||||
(defcustom elpy-django-server-command "runserver"
|
||||
"When executing `elpy-django-runserver' what should be the server
|
||||
command to use."
|
||||
:type 'string
|
||||
:safe 'stringp
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-server-command)
|
||||
|
||||
(defcustom elpy-django-always-prompt nil
|
||||
"When non-nil, it will always prompt for extra arguments
|
||||
to pass with the chosen command."
|
||||
:type 'boolean
|
||||
:safe 'booleanp
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-always-prompt)
|
||||
|
||||
(defcustom elpy-django-commands-with-req-arg '("startapp" "startproject"
|
||||
"loaddata" "sqlmigrate"
|
||||
"sqlsequencereset"
|
||||
"squashmigrations")
|
||||
"Used to determine if we should prompt for arguments. Some commands
|
||||
require arguments in order for it to work."
|
||||
:type 'list
|
||||
:safe 'listp
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-commands-with-req-arg)
|
||||
|
||||
(defcustom elpy-django-test-runner-formats '(("django_nose.NoseTestSuiteRunner" . ":")
|
||||
("django.test.runner.DiscoverRunner" . "."))
|
||||
"List of test runners and their format for calling tests.
|
||||
|
||||
Some tests runners are called differently. For example, Nose requires a ':' when calling specific tests,
|
||||
but the default Django test runner uses '.'"
|
||||
:type 'list
|
||||
:safe 'listp
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-test-runner-formats)
|
||||
|
||||
(defcustom elpy-django-test-runner-args '("test" "--noinput")
|
||||
"Arguments to pass to the test runner when calling tests."
|
||||
:type '(repeat string)
|
||||
:group 'elpy-django)
|
||||
(make-variable-buffer-local 'elpy-django-test-runner-args)
|
||||
|
||||
(defcustom elpy-test-django-runner-command nil
|
||||
"Deprecated. Please define Django command in `elpy-django-command' and
|
||||
test arguments in `elpy-django-test-runner-args'"
|
||||
:type '(repeat string)
|
||||
:group 'elpy-django)
|
||||
(make-obsolete-variable 'elpy-test-django-runner-command nil "March 2018")
|
||||
|
||||
(defcustom elpy-test-django-runner-manage-command nil
|
||||
"Deprecated. Please define Django command in `elpy-django-command' and
|
||||
test arguments in `elpy-django-test-runner-args'."
|
||||
:type '(repeat string)
|
||||
:group 'elpy-django)
|
||||
(make-obsolete-variable 'elpy-test-django-runner-manage-command nil "March 2018")
|
||||
|
||||
(defcustom elpy-test-django-with-manage nil
|
||||
"Deprecated. Please define Django command in `elpy-django-command' and
|
||||
test arguments in `elpy-django-test-runner-args'."
|
||||
:type 'boolean
|
||||
:group 'elpy-django)
|
||||
(make-obsolete-variable 'elpy-test-django-with-manage nil "March 2018")
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Key map
|
||||
|
||||
(defvar elpy-django-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "c") 'elpy-django-command)
|
||||
(define-key map (kbd "r") 'elpy-django-runserver)
|
||||
map)
|
||||
"Key map for django extension")
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; Helper Functions
|
||||
|
||||
(defun elpy-django-setup ()
|
||||
"Decides whether to start the minor mode or not."
|
||||
;; Make sure we're in an actual file and we can find
|
||||
;; manage.py. Otherwise user will have to manually
|
||||
;; start this mode if they're using 'django-admin.py'
|
||||
(when (locate-dominating-file default-directory "manage.py")
|
||||
;; Let's be nice and point to full path of 'manage.py'
|
||||
;; This only affects the buffer if there's no directory
|
||||
;; variable overwriting it.
|
||||
(setq elpy-django-command
|
||||
(expand-file-name (concat (locate-dominating-file default-directory "manage.py") "manage.py")))
|
||||
(elpy-django 1)))
|
||||
|
||||
(defun elpy-django--get-commands ()
|
||||
"Return list of django commands."
|
||||
(let ((dj-commands-str nil)
|
||||
(help-output
|
||||
(shell-command-to-string (concat elpy-django-command " -h"))))
|
||||
(setq dj-commands-str
|
||||
(with-temp-buffer
|
||||
(progn
|
||||
(insert help-output)
|
||||
(goto-char (point-min))
|
||||
(delete-region (point) (search-forward "Available subcommands:" nil nil nil))
|
||||
;; cleanup [auth] and stuff
|
||||
(goto-char (point-min))
|
||||
(save-excursion
|
||||
(while (re-search-forward "\\[.*\\]" nil t)
|
||||
(replace-match "" nil nil)))
|
||||
(buffer-string))))
|
||||
;; get a list of commands from the output of manage.py -h
|
||||
;; What would be the pattern to optimize this ?
|
||||
(setq dj-commands-str (split-string dj-commands-str "\n"))
|
||||
(setq dj-commands-str (cl-remove-if (lambda (x) (string= x "")) dj-commands-str))
|
||||
(setq dj-commands-str (mapcar (lambda (x) (s-trim x)) dj-commands-str))
|
||||
(sort dj-commands-str 'string-lessp)))
|
||||
|
||||
(defun elpy-django--get-test-runner ()
|
||||
"Return the name of the django test runner.
|
||||
Needs `DJANGO_SETTINGS_MODULE' to be set in order to work."
|
||||
(let ((django-import-cmd "import django;django.setup();from django.conf import settings;print(settings.TEST_RUNNER)")
|
||||
(django-settings-env (getenv "DJANGO_SETTINGS_MODULE"))
|
||||
(default-directory (elpy-project-root)))
|
||||
;; If no Django settings has been set, then nothing will work. Warn user
|
||||
(when (not django-settings-env)
|
||||
(error "Please set environment variable `DJANGO_SETTINGS_MODULE' if you'd like to run the test runner"))
|
||||
|
||||
;; We have to be able to import the DJANGO_SETTINGS_MODULE otherwise it will also break
|
||||
;; If we get a traceback when import django settings, then warn the user that settings is not valid
|
||||
(when (not (string= "" (shell-command-to-string
|
||||
(format "%s -c 'import %s'" elpy-rpc-python-command django-settings-env))))
|
||||
(error (format "Unable to import DJANGO_SETTINGS_MODULE: '%s'" django-settings-env)))
|
||||
|
||||
;; Return test runner
|
||||
(s-trim (shell-command-to-string
|
||||
(format "%s -c '%s'" elpy-rpc-python-command django-import-cmd)))))
|
||||
|
||||
(defun elpy-django--get-test-format ()
|
||||
"When running a Django test, some test runners require a different format that others.
|
||||
Return the correct string format here."
|
||||
(let ((pair (assoc (elpy-django--get-test-runner) elpy-django-test-runner-formats)))
|
||||
(if pair
|
||||
;; Return the associated test format
|
||||
(cdr pair)
|
||||
(error (format "Unable to find test format for `%s'" (elpy--get-django-test-runner))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; User Functions
|
||||
|
||||
(defun elpy-django-command (cmd)
|
||||
"Prompt user for Django command. If called with `C-u',
|
||||
it will prompt for other flags/arguments to run."
|
||||
(interactive (list (completing-read "Command: " (elpy-django--get-commands) nil nil)))
|
||||
;; Called with C-u, variable is set or is a cmd that requires an argument
|
||||
(when (or current-prefix-arg
|
||||
elpy-django-always-prompt
|
||||
(member cmd elpy-django-commands-with-req-arg))
|
||||
(setq cmd (concat cmd " " (read-shell-command (concat cmd ": ") "--noinput"))))
|
||||
(compile (concat elpy-django-command " " cmd)))
|
||||
|
||||
(defun elpy-django-runserver (arg)
|
||||
"Start the server and automatically add the ipaddr and port.
|
||||
Also create it's own special buffer so that we can have multiple
|
||||
servers running per project.
|
||||
|
||||
When called with a prefix (C-u), it will prompt for additional args."
|
||||
(interactive "P")
|
||||
(let* ((cmd (concat elpy-django-command " " elpy-django-server-command))
|
||||
(proj-root (file-name-base (directory-file-name (elpy-project-root))))
|
||||
(buff-name (format "*runserver[%s]*" proj-root)))
|
||||
;; Kill any previous instance of runserver since we might be doing something new
|
||||
(when (get-buffer buff-name)
|
||||
(kill-buffer buff-name))
|
||||
(setq cmd (concat cmd " " elpy-django-server-ipaddr ":" elpy-django-server-port))
|
||||
(when (or arg elpy-django-always-prompt)
|
||||
(setq cmd (concat cmd " "(read-shell-command (concat cmd ": ")))))
|
||||
(compile cmd)
|
||||
(with-current-buffer "*compilation*"
|
||||
(rename-buffer buff-name))))
|
||||
|
||||
(defun elpy-test-django-runner (top _file module test)
|
||||
"Test the project using the Django discover runner,
|
||||
or with manage.py if elpy-test-django-with-manage is true.
|
||||
|
||||
This requires Django 1.6 or the django-discover-runner package."
|
||||
(interactive (elpy-test-at-point))
|
||||
(if module
|
||||
(apply #'elpy-test-run
|
||||
top
|
||||
(append
|
||||
(list elpy-django-command)
|
||||
elpy-django-test-runner-args
|
||||
(list (if test
|
||||
(format "%s%s%s" module (elpy-django--get-test-format) test)
|
||||
module))))
|
||||
(apply #'elpy-test-run
|
||||
top
|
||||
(append
|
||||
(list elpy-django-command)
|
||||
elpy-django-test-runner-args))))
|
||||
(put 'elpy-test-django-runner 'elpy-test-runner-p t)
|
||||
|
||||
(define-minor-mode elpy-django
|
||||
"Minor mode for Django commands."
|
||||
:group 'elpy-django)
|
||||
|
||||
(provide 'elpy-django)
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; elpy-django.el ends here
|
Binary file not shown.
|
@ -0,0 +1,11 @@
|
|||
(define-package "elpy" "20180831.846" "Emacs Python Development Environment"
|
||||
'((company "0.9.2")
|
||||
(emacs "24.4")
|
||||
(find-file-in-project "3.3")
|
||||
(highlight-indentation "0.5.0")
|
||||
(pyvenv "1.3")
|
||||
(yasnippet "0.8.0")
|
||||
(s "1.11.0")))
|
||||
;; Local Variables:
|
||||
;; no-byte-compile: t
|
||||
;; End:
|
|
@ -0,0 +1,111 @@
|
|||
;;; elpy-profile.el --- Profiling capabilitiss for elpy
|
||||
|
||||
;; Copyright (C) 2013-2016 Jorgen Schaefer
|
||||
|
||||
;; Author: Gaby Launay <gaby.launay@tutanota.com>
|
||||
;; URL: https://github.com/jorgenschaefer/elpy
|
||||
|
||||
;; This program is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU General Public License
|
||||
;; as published by the Free Software Foundation; either version 3
|
||||
;; of the License, or (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file serves as an extension to elpy by adding profiling capabilities
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; User customization
|
||||
|
||||
(defcustom elpy-profile-visualizer "snakeviz"
|
||||
"Visualizer for elpy profile results."
|
||||
:type 'str
|
||||
:group 'elpy)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; Helper Functions
|
||||
|
||||
(defun elpy-profile--display-profiling (file)
|
||||
"Display the profile result FILE using `elpy-profile-visualizer'."
|
||||
(let ((exec (car (split-string elpy-profile-visualizer " " t)))
|
||||
(args (append (cdr (split-string elpy-profile-visualizer " " t)) (list file))))
|
||||
(if (executable-find exec)
|
||||
(apply 'call-process exec nil 0 nil args)
|
||||
(message "Elpy profile visualizer '%s' not found" exec))))
|
||||
|
||||
(defun elpy-profile--sentinel (process string)
|
||||
"Elpy profile sentinel."
|
||||
(let ((filename (file-name-nondirectory (process-get process 'file)))
|
||||
(prof-file (process-get process 'prof-file))
|
||||
(dont-display (process-get process 'dont-display)))
|
||||
(with-current-buffer "*elpy-profile-log*"
|
||||
(view-mode))
|
||||
(if (not (string-equal string "finished\n"))
|
||||
(progn
|
||||
(message "[%s] Profiling failed" filename)
|
||||
(display-buffer "*elpy-profile-log*"))
|
||||
(message "[%s] Profiling succeeded" filename)
|
||||
(when (not dont-display)
|
||||
(elpy-profile--display-profiling prof-file)))))
|
||||
|
||||
(defun elpy-profile--file (file &optional in-dir dont-display)
|
||||
"Profile asynchronously FILE and display the result using
|
||||
`elpy-profile-visualizer'.
|
||||
|
||||
If IN-DIR is non nil, profile result is saved in the same
|
||||
directory as the script.
|
||||
If DONT-DISPLAY is non nil, don't display the profile results."
|
||||
(ignore-errors (kill-buffer "*elpy-profile-log*"))
|
||||
(let* ((prof-file (if in-dir
|
||||
(concat (file-name-sans-extension file) ".profile")
|
||||
(concat (make-temp-file "elpy-profile-" nil ".profile"))))
|
||||
(proc-name (format "elpy-profile-%s" file))
|
||||
(proc-cmd (list python-shell-interpreter "-m" "cProfile" "-o" prof-file file))
|
||||
(proc (make-process :name proc-name
|
||||
:buffer "*elpy-profile-log*"
|
||||
:sentinel 'elpy-profile--sentinel
|
||||
:command proc-cmd)))
|
||||
(message "[%s] Profiling ..." (file-name-nondirectory file))
|
||||
(process-put proc 'prof-file prof-file)
|
||||
(process-put proc 'file file)
|
||||
(process-put proc 'dont-display dont-display)
|
||||
prof-file))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; User Functions
|
||||
|
||||
(defun elpy-profile-buffer-or-region (&optional in-dir dont-display)
|
||||
"Profile asynchronously the active region or the current buffer
|
||||
and display the result using `elpy-profile-visualizer'.
|
||||
|
||||
If IN-DIR is non nil, profile result is saved in the same
|
||||
directory as the script.
|
||||
If DONT-DISPLAY is non nil, don't display the profile results."
|
||||
(interactive "P")
|
||||
(let* ((file-name (buffer-name))
|
||||
(file-dir (file-name-directory (buffer-file-name)))
|
||||
(beg (if (region-active-p) (region-beginning) (point-min)))
|
||||
(end (if (region-active-p) (region-end) (point-max)))
|
||||
(tmp-file-prefix (if (region-active-p) "_region_" ""))
|
||||
(tmp-file (if in-dir
|
||||
(concat file-dir "/" tmp-file-prefix file-name)
|
||||
(concat (make-temp-file "elpy-profile-" t) "/" tmp-file-prefix file-name)))
|
||||
(region (elpy-shell--region-without-indentation beg end)))
|
||||
(with-temp-buffer
|
||||
(insert region)
|
||||
(write-region (point-min) (point-max) tmp-file nil t))
|
||||
(elpy-profile--file tmp-file t dont-display)))
|
||||
|
||||
(provide 'elpy-profile)
|
||||
;;; elpy-profile.el ends here
|
Binary file not shown.
|
@ -0,0 +1,297 @@
|
|||
;;; elpy-refactor.el --- Refactoring mode for Elpy
|
||||
|
||||
;; Copyright (C) 2013-2016 Jorgen Schaefer
|
||||
|
||||
;; Author: Jorgen Schaefer <contact@jorgenschaefer.de>
|
||||
;; URL: https://github.com/jorgenschaefer/elpy
|
||||
|
||||
;; This program is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU General Public License
|
||||
;; as published by the Free Software Foundation; either version 3
|
||||
;; of the License, or (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file provides an interface, including a major mode, to use
|
||||
;; refactoring options provided by the Rope library.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; We require elpy, but elpy loads us, so we shouldn't load it back.
|
||||
;; (require 'elpy)
|
||||
|
||||
(defvar elpy-refactor-changes nil
|
||||
"Changes that will be commited on \\[elpy-refactor-commit].")
|
||||
(make-variable-buffer-local 'elpy-refactor-current-changes)
|
||||
|
||||
(defvar elpy-refactor-window-configuration nil
|
||||
"The old window configuration. Will be restored after commit.")
|
||||
(make-variable-buffer-local 'elpy-refactor-window-configuration)
|
||||
|
||||
(make-obsolete
|
||||
'elpy-refactor
|
||||
"Refactoring has been unstable and flakey, support will be dropped in the future."
|
||||
"elpy 1.5.0")
|
||||
(defun elpy-refactor ()
|
||||
"Run the Elpy refactoring interface for Python code."
|
||||
(interactive)
|
||||
(save-some-buffers)
|
||||
(let* ((selection (elpy-refactor-select
|
||||
(elpy-refactor-rpc-get-options)))
|
||||
(method (car selection))
|
||||
(args (cdr selection)))
|
||||
(when method
|
||||
(elpy-refactor-create-change-buffer
|
||||
(elpy-refactor-rpc-get-changes method args)))))
|
||||
|
||||
(defun elpy-refactor-select (options)
|
||||
"Show the user the refactoring options and let her choose one.
|
||||
|
||||
Depending on the chosen option, ask the user for further
|
||||
arguments and build the argument.
|
||||
|
||||
Return a cons cell of the name of the option and the arg list
|
||||
created."
|
||||
(let ((buf (get-buffer-create "*Elpy Refactor*"))
|
||||
(pos (vector (1- (point))
|
||||
(ignore-errors
|
||||
(1- (region-beginning)))
|
||||
(ignore-errors
|
||||
(1- (region-end)))))
|
||||
(inhibit-read-only t)
|
||||
(options (sort options
|
||||
(lambda (a b)
|
||||
(let ((cata (cdr (assq 'category a)))
|
||||
(catb (cdr (assq 'category b))))
|
||||
(if (equal cata catb)
|
||||
(string< (cdr (assq 'description a))
|
||||
(cdr (assq 'description b)))
|
||||
(string< cata catb))))))
|
||||
(key ?a)
|
||||
last-category
|
||||
option-alist)
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(dolist (option options)
|
||||
(let ((category (cdr (assq 'category option)))
|
||||
(description (cdr (assq 'description option)))
|
||||
(name (cdr (assq 'name option)))
|
||||
(args (cdr (assq 'args option))))
|
||||
(when (not (equal category last-category))
|
||||
(when last-category
|
||||
(insert "\n"))
|
||||
(insert (propertize category 'face 'bold) "\n")
|
||||
(setq last-category category))
|
||||
(insert " (" key ") " description "\n")
|
||||
(setq option-alist (cons (list key name args)
|
||||
option-alist))
|
||||
(setq key (1+ key))))
|
||||
(let ((window-conf (current-window-configuration)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(with-selected-window (display-buffer buf)
|
||||
(goto-char (point-min)))
|
||||
(fit-window-to-buffer (get-buffer-window buf))
|
||||
(let* ((key (read-key "Refactoring action? "))
|
||||
(entry (cdr (assoc key option-alist))))
|
||||
(kill-buffer buf)
|
||||
(cons (car entry) ; name
|
||||
(elpy-refactor-build-arguments (cadr entry)
|
||||
pos))))
|
||||
(set-window-configuration window-conf))))))
|
||||
|
||||
(defun elpy-refactor-build-arguments (args pos)
|
||||
"Translate an argument list specification to an argument list.
|
||||
|
||||
POS is a vector of three elements, the current offset, the offset
|
||||
of the beginning of the region, and the offset of the end of the
|
||||
region.
|
||||
|
||||
ARGS is a list of triples, each triple containing the name of an
|
||||
argument (ignored), the type of the argument, and a possible
|
||||
prompt string.
|
||||
|
||||
Available types:
|
||||
|
||||
offset - The offset in the buffer, (1- (point))
|
||||
start_offset - Offset of the beginning of the region
|
||||
end_offset - Offset of the end of the region
|
||||
string - A free-form string
|
||||
filename - A non-existing file name
|
||||
directory - An existing directory name
|
||||
boolean - A boolean question"
|
||||
(mapcar (lambda (arg)
|
||||
(let ((type (cadr arg))
|
||||
(prompt (cl-caddr arg)))
|
||||
(cond
|
||||
((equal type "offset")
|
||||
(aref pos 0))
|
||||
((equal type "start_offset")
|
||||
(aref pos 1))
|
||||
((equal type "end_offset")
|
||||
(aref pos 2))
|
||||
((equal type "string")
|
||||
(read-from-minibuffer prompt))
|
||||
((equal type "filename")
|
||||
(expand-file-name
|
||||
(read-file-name prompt)))
|
||||
((equal type "directory")
|
||||
(expand-file-name
|
||||
(read-directory-name prompt)))
|
||||
((equal type "boolean")
|
||||
(y-or-n-p prompt)))))
|
||||
args))
|
||||
|
||||
(defun elpy-refactor-create-change-buffer (changes)
|
||||
"Show the user a buffer of changes.
|
||||
|
||||
The user can review the changes and confirm them with
|
||||
\\[elpy-refactor-commit]."
|
||||
(when (not changes)
|
||||
(error "No changes for this refactoring action."))
|
||||
(with-current-buffer (get-buffer-create "*Elpy Refactor*")
|
||||
(elpy-refactor-mode)
|
||||
(setq elpy-refactor-changes changes
|
||||
elpy-refactor-window-configuration (current-window-configuration))
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(elpy-refactor-insert-changes changes))
|
||||
(select-window (display-buffer (current-buffer)))
|
||||
(goto-char (point-min))))
|
||||
|
||||
(defun elpy-refactor-insert-changes (changes)
|
||||
"Format and display the changes described in CHANGES."
|
||||
(insert (propertize "Use C-c C-c to apply the following changes."
|
||||
'face 'bold)
|
||||
"\n\n")
|
||||
(dolist (change changes)
|
||||
(let ((action (cdr (assq 'action change))))
|
||||
(cond
|
||||
((equal action "change")
|
||||
(insert (cdr (assq 'diff change))
|
||||
"\n"))
|
||||
((equal action "create")
|
||||
(let ((type (cdr (assq 'type change))))
|
||||
(if (equal type "file")
|
||||
(insert "+++ " (cdr (assq 'file change)) "\n"
|
||||
"Create file " (cdr (assq 'file change)) "\n"
|
||||
"\n")
|
||||
(insert "+++ " (cdr (assq 'path change)) "\n"
|
||||
"Create directory " (cdr (assq 'path change)) "\n"
|
||||
"\n"))))
|
||||
((equal action "move")
|
||||
(insert "--- " (cdr (assq 'source change)) "\n"
|
||||
"+++ " (cdr (assq 'destination change)) "\n"
|
||||
"Rename " (cdr (assq 'type change)) "\n"
|
||||
"\n"))
|
||||
((equal action "delete")
|
||||
(let ((type (cdr (assq 'type change))))
|
||||
(if (equal type "file")
|
||||
(insert "--- " (cdr (assq 'file change)) "\n"
|
||||
"Delete file " (cdr (assq 'file change)) "\n"
|
||||
"\n")
|
||||
(insert "--- " (cdr (assq 'path change)) "\n"
|
||||
"Delete directory " (cdr (assq 'path change)) "\n"
|
||||
"\n"))))))))
|
||||
|
||||
(defvar elpy-refactor-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "C-c C-c") 'elpy-refactor-commit)
|
||||
(define-key map (kbd "q") 'bury-buffer)
|
||||
(define-key map (kbd "h") 'describe-mode)
|
||||
(define-key map (kbd "?") 'describe-mode)
|
||||
map)
|
||||
"The key map for `elpy-refactor-mode'.")
|
||||
|
||||
(define-derived-mode elpy-refactor-mode diff-mode "Elpy Refactor"
|
||||
"Mode to display refactoring actions and ask confirmation from the user.
|
||||
|
||||
\\{elpy-refactor-mode-map}"
|
||||
:group 'elpy
|
||||
(view-mode 1))
|
||||
|
||||
(defun elpy-refactor-commit ()
|
||||
"Commit the changes in the current buffer."
|
||||
(interactive)
|
||||
(when (not elpy-refactor-changes)
|
||||
(error "No changes to commit."))
|
||||
;; Restore the window configuration as the first thing so that
|
||||
;; changes below are visible to the user. Especially the point
|
||||
;; change in possible buffer changes.
|
||||
(set-window-configuration elpy-refactor-window-configuration)
|
||||
(dolist (change elpy-refactor-changes)
|
||||
(let ((action (cdr (assq 'action change))))
|
||||
(cond
|
||||
((equal action "change")
|
||||
(with-current-buffer (find-file-noselect (cdr (assq 'file change)))
|
||||
;; This would break for save-excursion as the buffer is
|
||||
;; truncated, so all markets now point to position 1.
|
||||
(let ((old-point (point)))
|
||||
(undo-boundary)
|
||||
(erase-buffer)
|
||||
(insert (cdr (assq 'contents change)))
|
||||
(undo-boundary)
|
||||
(goto-char old-point))))
|
||||
((equal action "create")
|
||||
(if (equal (cdr (assq 'type change))
|
||||
"file")
|
||||
(find-file-noselect (cdr (assq 'file change)))
|
||||
(make-directory (cdr (assq 'path change)))))
|
||||
((equal action "move")
|
||||
(let* ((source (cdr (assq 'source change)))
|
||||
(dest (cdr (assq 'destination change)))
|
||||
(buf (get-file-buffer source)))
|
||||
(when buf
|
||||
(with-current-buffer buf
|
||||
(setq buffer-file-name dest)
|
||||
(rename-buffer (file-name-nondirectory dest) t)))
|
||||
(rename-file source dest)))
|
||||
((equal action "delete")
|
||||
(if (equal (cdr (assq 'type change)) "file")
|
||||
(let ((name (cdr (assq 'file change))))
|
||||
(when (y-or-n-p (format "Really delete %s? " name))
|
||||
(delete-file name t)))
|
||||
(let ((name (cdr (assq 'directory change))))
|
||||
(when (y-or-n-p (format "Really delete %s? " name))
|
||||
(delete-directory name nil t))))))))
|
||||
(kill-buffer (current-buffer)))
|
||||
|
||||
(defun elpy-refactor-rpc-get-options ()
|
||||
"Get a list of refactoring options from the Elpy RPC."
|
||||
(if (use-region-p)
|
||||
(elpy-rpc "get_refactor_options"
|
||||
(list (buffer-file-name)
|
||||
(1- (region-beginning))
|
||||
(1- (region-end))))
|
||||
(elpy-rpc "get_refactor_options"
|
||||
(list (buffer-file-name)
|
||||
(1- (point))))))
|
||||
|
||||
(defun elpy-refactor-rpc-get-changes (method args)
|
||||
"Get a list of changes from the Elpy RPC after applying METHOD with ARGS."
|
||||
(elpy-rpc "refactor"
|
||||
(list (buffer-file-name)
|
||||
method args)))
|
||||
|
||||
(defun elpy-refactor-options (option)
|
||||
"Show available refactor options and let user choose one."
|
||||
(interactive "c[i]: importmagic-fixup [p]: autopep8-fix-code [r]: refactor")
|
||||
(let ((choice (char-to-string option)))
|
||||
(cond
|
||||
((string-equal choice "i")
|
||||
(elpy-importmagic-fixup))
|
||||
((string-equal choice "p")
|
||||
(elpy-autopep8-fix-code))
|
||||
((string-equal choice "r")
|
||||
(elpy-refactor)))))
|
||||
|
||||
(provide 'elpy-refactor)
|
||||
;;; elpy-refactor.el ends here
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
|||
# Elpy, the Emacs Lisp Python Environment
|
||||
|
||||
# Copyright (C) 2013-2016 Jorgen Schaefer
|
||||
|
||||
# Author: Jorgen Schaefer <contact@jorgenschaefer.de>
|
||||
# URL: http://github.com/jorgenschaefer/elpy
|
||||
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 3
|
||||
# of the License, or (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""The Emacs Lisp Python Environment.
|
||||
|
||||
Elpy is a mode for Emacs to support writing Python code. This package
|
||||
provides the backend within Python to support auto-completion,
|
||||
documentation extraction, and navigation.
|
||||
|
||||
Emacs will start the protocol by running the module itself, like so:
|
||||
|
||||
python -m elpy
|
||||
|
||||
This will emit a greeting string on a single line, and then wait for
|
||||
the protocol to start. Details of the protocol can be found in
|
||||
elpy.rpc.
|
||||
|
||||
This package is unlikely to be useful on its own.
|
||||
|
||||
"""
|
||||
|
||||
__author__ = "Jorgen Schaefer"
|
||||
__version__ = "1.24.0"
|
||||
__license__ = "GPL"
|
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
"""Main interface to the RPC server.
|
||||
|
||||
You should be able to just run the following to use this module:
|
||||
|
||||
python -m elpy
|
||||
|
||||
The first line should be "elpy-rpc ready". If it isn't, something
|
||||
broke.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import elpy
|
||||
from elpy.server import ElpyRPCServer
|
||||
|
||||
if __name__ == '__main__':
|
||||
stdin = sys.stdin
|
||||
stdout = sys.stdout
|
||||
sys.stdout = sys.stderr = open(os.devnull, "w")
|
||||
stdout.write('elpy-rpc ready ({0})\n'
|
||||
.format(elpy.__version__))
|
||||
stdout.flush()
|
||||
ElpyRPCServer(stdin, stdout).serve_forever()
|
|
@ -0,0 +1,27 @@
|
|||
"""Glue for the "autopep8" library.
|
||||
|
||||
"""
|
||||
|
||||
from elpy.rpc import Fault
|
||||
import os
|
||||
|
||||
|
||||
try:
|
||||
import autopep8
|
||||
except ImportError: # pragma: no cover
|
||||
autopep8 = None
|
||||
|
||||
|
||||
def fix_code(code, directory):
|
||||
"""Formats Python code to conform to the PEP 8 style guide.
|
||||
|
||||
"""
|
||||
if not autopep8:
|
||||
raise Fault('autopep8 not installed, cannot fix code.',
|
||||
code=400)
|
||||
old_dir = os.getcwd()
|
||||
try:
|
||||
os.chdir(directory)
|
||||
return autopep8.fix_code(code, apply_config=True)
|
||||
finally:
|
||||
os.chdir(old_dir)
|
Binary file not shown.
|
@ -0,0 +1,39 @@
|
|||
"""Glue for the "black" library.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from elpy.rpc import Fault
|
||||
|
||||
BLACK_NOT_SUPPORTED = sys.version_info < (3, 6)
|
||||
|
||||
try:
|
||||
if BLACK_NOT_SUPPORTED:
|
||||
black = None
|
||||
else:
|
||||
import black
|
||||
except ImportError: # pragma: no cover
|
||||
black = None
|
||||
|
||||
|
||||
def fix_code(code, directory):
|
||||
"""Formats Python code to conform to the PEP 8 style guide.
|
||||
|
||||
"""
|
||||
if not black:
|
||||
raise Fault('black not installed', code=400)
|
||||
|
||||
try:
|
||||
reformatted_source = black.format_file_contents(
|
||||
src_contents=code,
|
||||
line_length=black.DEFAULT_LINE_LENGTH,
|
||||
fast=False
|
||||
)
|
||||
return reformatted_source
|
||||
except black.NothingChanged:
|
||||
return code
|
||||
except Exception as e:
|
||||
raise Fault("Error during formatting: {}".format(e),
|
||||
code=400)
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
"""Python 2/3 compatibility definitions.
|
||||
|
||||
These are used by the rest of Elpy to keep compatibility definitions
|
||||
in one place.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
PYTHON3 = True
|
||||
|
||||
from io import StringIO
|
||||
|
||||
def ensure_not_unicode(obj):
|
||||
return obj
|
||||
else:
|
||||
PYTHON3 = False
|
||||
|
||||
from StringIO import StringIO # noqa
|
||||
|
||||
def ensure_not_unicode(obj):
|
||||
"""Return obj. If it's a unicode string, convert it to str first.
|
||||
|
||||
Pydoc functions simply don't find anything for unicode
|
||||
strings. No idea why.
|
||||
|
||||
"""
|
||||
if isinstance(obj, unicode):
|
||||
return obj.encode("utf-8")
|
||||
else:
|
||||
return obj
|
Binary file not shown.
|
@ -0,0 +1,305 @@
|
|||
"""Elpy backend using the Jedi library.
|
||||
|
||||
This backend uses the Jedi library:
|
||||
|
||||
https://github.com/davidhalter/jedi
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
import re
|
||||
|
||||
import jedi
|
||||
|
||||
from elpy import rpc
|
||||
|
||||
|
||||
class JediBackend(object):
|
||||
"""The Jedi backend class.
|
||||
|
||||
Implements the RPC calls we can pass on to Jedi.
|
||||
|
||||
Documentation: http://jedi.jedidjah.ch/en/latest/docs/plugin-api.html
|
||||
|
||||
"""
|
||||
name = "jedi"
|
||||
|
||||
def __init__(self, project_root):
|
||||
self.project_root = project_root
|
||||
self.completions = {}
|
||||
sys.path.append(project_root)
|
||||
|
||||
def rpc_get_completions(self, filename, source, offset):
|
||||
line, column = pos_to_linecol(source, offset)
|
||||
proposals = run_with_debug(jedi, 'completions',
|
||||
source=source, line=line, column=column,
|
||||
path=filename, encoding='utf-8')
|
||||
if proposals is None:
|
||||
return []
|
||||
self.completions = dict((proposal.name, proposal)
|
||||
for proposal in proposals)
|
||||
return [{'name': proposal.name.rstrip("="),
|
||||
'suffix': proposal.complete.rstrip("="),
|
||||
'annotation': proposal.type,
|
||||
'meta': proposal.description}
|
||||
for proposal in proposals]
|
||||
|
||||
def rpc_get_completion_docstring(self, completion):
|
||||
proposal = self.completions.get(completion)
|
||||
if proposal is None:
|
||||
return None
|
||||
else:
|
||||
return proposal.docstring(fast=False)
|
||||
|
||||
def rpc_get_completion_location(self, completion):
|
||||
proposal = self.completions.get(completion)
|
||||
if proposal is None:
|
||||
return None
|
||||
else:
|
||||
return (proposal.module_path, proposal.line)
|
||||
|
||||
def rpc_get_docstring(self, filename, source, offset):
|
||||
line, column = pos_to_linecol(source, offset)
|
||||
locations = run_with_debug(jedi, 'goto_definitions',
|
||||
source=source, line=line, column=column,
|
||||
path=filename, encoding='utf-8')
|
||||
if locations and locations[-1].docstring():
|
||||
return ('Documentation for {0}:\n\n'.format(
|
||||
locations[-1].full_name) + locations[-1].docstring())
|
||||
else:
|
||||
return None
|
||||
|
||||
def rpc_get_definition(self, filename, source, offset):
|
||||
line, column = pos_to_linecol(source, offset)
|
||||
locations = run_with_debug(jedi, 'goto_definitions',
|
||||
source=source, line=line, column=column,
|
||||
path=filename, encoding='utf-8')
|
||||
# goto_definitions() can return silly stuff like __builtin__
|
||||
# for int variables, so we fall back on goto() in those
|
||||
# cases. See issue #76.
|
||||
if (
|
||||
locations and
|
||||
locations[0].module_path is None
|
||||
):
|
||||
locations = run_with_debug(jedi, 'goto_assignments',
|
||||
source=source, line=line,
|
||||
column=column,
|
||||
path=filename, encoding='utf-8')
|
||||
if not locations:
|
||||
return None
|
||||
else:
|
||||
loc = locations[-1]
|
||||
try:
|
||||
if loc.module_path:
|
||||
if loc.module_path == filename:
|
||||
offset = linecol_to_pos(source,
|
||||
loc.line,
|
||||
loc.column)
|
||||
else:
|
||||
with open(loc.module_path) as f:
|
||||
offset = linecol_to_pos(f.read(),
|
||||
loc.line,
|
||||
loc.column)
|
||||
else:
|
||||
return None
|
||||
except IOError:
|
||||
return None
|
||||
return (loc.module_path, offset)
|
||||
|
||||
def rpc_get_assignment(self, filename, source, offset):
|
||||
line, column = pos_to_linecol(source, offset)
|
||||
locations = run_with_debug(jedi, 'goto_assignments',
|
||||
source=source, line=line, column=column,
|
||||
path=filename, encoding='utf-8')
|
||||
if not locations:
|
||||
return None
|
||||
else:
|
||||
loc = locations[-1]
|
||||
try:
|
||||
if loc.module_path:
|
||||
if loc.module_path == filename:
|
||||
offset = linecol_to_pos(source,
|
||||
loc.line,
|
||||
loc.column)
|
||||
else:
|
||||
with open(loc.module_path) as f:
|
||||
offset = linecol_to_pos(f.read(),
|
||||
loc.line,
|
||||
loc.column)
|
||||
else:
|
||||
return None
|
||||
except IOError:
|
||||
return None
|
||||
return (loc.module_path, offset)
|
||||
|
||||
def rpc_get_calltip(self, filename, source, offset):
|
||||
line, column = pos_to_linecol(source, offset)
|
||||
calls = run_with_debug(jedi, 'call_signatures',
|
||||
source=source, line=line, column=column,
|
||||
path=filename, encoding='utf-8')
|
||||
if calls:
|
||||
call = calls[0]
|
||||
else:
|
||||
call = None
|
||||
if not call:
|
||||
return None
|
||||
# Strip 'param' added by jedi at the beggining of
|
||||
# parameter names. Should be unecessary for jedi > 0.13.0
|
||||
params = [re.sub("^param ", '', param.description)
|
||||
for param in call.params]
|
||||
return {"name": call.name,
|
||||
"index": call.index,
|
||||
"params": params}
|
||||
|
||||
def rpc_get_usages(self, filename, source, offset):
|
||||
"""Return the uses of the symbol at offset.
|
||||
|
||||
Returns a list of occurrences of the symbol, as dicts with the
|
||||
fields name, filename, and offset.
|
||||
|
||||
"""
|
||||
line, column = pos_to_linecol(source, offset)
|
||||
uses = run_with_debug(jedi, 'usages',
|
||||
source=source, line=line, column=column,
|
||||
path=filename, encoding='utf-8')
|
||||
if uses is None:
|
||||
return None
|
||||
result = []
|
||||
for use in uses:
|
||||
if use.module_path == filename:
|
||||
offset = linecol_to_pos(source, use.line, use.column)
|
||||
elif use.module_path is not None:
|
||||
with open(use.module_path) as f:
|
||||
text = f.read()
|
||||
offset = linecol_to_pos(text, use.line, use.column)
|
||||
|
||||
result.append({"name": use.name,
|
||||
"filename": use.module_path,
|
||||
"offset": offset})
|
||||
|
||||
return result
|
||||
|
||||
def rpc_get_names(self, filename, source, offset):
|
||||
"""Return the list of possible names"""
|
||||
names = jedi.api.names(source=source,
|
||||
path=filename, encoding='utf-8',
|
||||
all_scopes=True,
|
||||
definitions=True,
|
||||
references=True)
|
||||
|
||||
result = []
|
||||
for name in names:
|
||||
if name.module_path == filename:
|
||||
offset = linecol_to_pos(source, name.line, name.column)
|
||||
elif name.module_path is not None:
|
||||
with open(name.module_path) as f:
|
||||
text = f.read()
|
||||
offset = linecol_to_pos(text, name.line, name.column)
|
||||
result.append({"name": name.name,
|
||||
"filename": name.module_path,
|
||||
"offset": offset})
|
||||
return result
|
||||
|
||||
|
||||
# From the Jedi documentation:
|
||||
#
|
||||
# line is the current line you want to perform actions on (starting
|
||||
# with line #1 as the first line). column represents the current
|
||||
# column/indent of the cursor (starting with zero). source_path
|
||||
# should be the path of your file in the file system.
|
||||
|
||||
def pos_to_linecol(text, pos):
|
||||
"""Return a tuple of line and column for offset pos in text.
|
||||
|
||||
Lines are one-based, columns zero-based.
|
||||
|
||||
This is how Jedi wants it. Don't ask me why.
|
||||
|
||||
"""
|
||||
line_start = text.rfind("\n", 0, pos) + 1
|
||||
line = text.count("\n", 0, line_start) + 1
|
||||
col = pos - line_start
|
||||
return line, col
|
||||
|
||||
|
||||
def linecol_to_pos(text, line, col):
|
||||
"""Return the offset of this line and column in text.
|
||||
|
||||
Lines are one-based, columns zero-based.
|
||||
|
||||
This is how Jedi wants it. Don't ask me why.
|
||||
|
||||
"""
|
||||
nth_newline_offset = 0
|
||||
for i in range(line - 1):
|
||||
new_offset = text.find("\n", nth_newline_offset)
|
||||
if new_offset < 0:
|
||||
raise ValueError("Text does not have {0} lines."
|
||||
.format(line))
|
||||
nth_newline_offset = new_offset + 1
|
||||
offset = nth_newline_offset + col
|
||||
if offset > len(text):
|
||||
raise ValueError("Line {0} column {1} is not within the text"
|
||||
.format(line, col))
|
||||
return offset
|
||||
|
||||
|
||||
def run_with_debug(jedi, name, *args, **kwargs):
|
||||
re_raise = kwargs.pop('re_raise', ())
|
||||
try:
|
||||
script = jedi.Script(*args, **kwargs)
|
||||
return getattr(script, name)()
|
||||
except Exception as e:
|
||||
if isinstance(e, re_raise):
|
||||
raise
|
||||
# Bug jedi#485
|
||||
if (
|
||||
isinstance(e, ValueError) and
|
||||
"invalid \\x escape" in str(e)
|
||||
):
|
||||
return None
|
||||
# Bug jedi#485 in Python 3
|
||||
if (
|
||||
isinstance(e, SyntaxError) and
|
||||
"truncated \\xXX escape" in str(e)
|
||||
):
|
||||
return None
|
||||
|
||||
from jedi import debug
|
||||
|
||||
debug_info = []
|
||||
|
||||
def _debug(level, str_out):
|
||||
if level == debug.NOTICE:
|
||||
prefix = "[N]"
|
||||
elif level == debug.WARNING:
|
||||
prefix = "[W]"
|
||||
else:
|
||||
prefix = "[?]"
|
||||
debug_info.append(u"{0} {1}".format(prefix, str_out))
|
||||
|
||||
jedi.set_debug_function(_debug, speed=False)
|
||||
try:
|
||||
script = jedi.Script(*args, **kwargs)
|
||||
return getattr(script, name)()
|
||||
except Exception as e:
|
||||
source = kwargs.get('source')
|
||||
sc_args = []
|
||||
sc_args.extend(repr(arg) for arg in args)
|
||||
sc_args.extend("{0}={1}".format(k, "source" if k == "source"
|
||||
else repr(v))
|
||||
for (k, v) in kwargs.items())
|
||||
|
||||
data = {
|
||||
"traceback": traceback.format_exc(),
|
||||
"jedi_debug_info": {'script_args': ", ".join(sc_args),
|
||||
'source': source,
|
||||
'method': name,
|
||||
'debug_info': debug_info}
|
||||
}
|
||||
raise rpc.Fault(message=str(e),
|
||||
code=500,
|
||||
data=data)
|
||||
finally:
|
||||
jedi.set_debug_function(None)
|
Binary file not shown.
|
@ -0,0 +1,91 @@
|
|||
import sys
|
||||
import types
|
||||
|
||||
from pydoc import safeimport, resolve, ErrorDuringImport
|
||||
from pkgutil import iter_modules
|
||||
|
||||
from elpy import compat
|
||||
|
||||
# Types we want to recurse into (nodes).
|
||||
CONTAINER_TYPES = (type, types.ModuleType)
|
||||
# Types of attributes we can get documentation for (leaves).
|
||||
PYDOC_TYPES = (type,
|
||||
types.FunctionType,
|
||||
types.BuiltinFunctionType,
|
||||
types.BuiltinMethodType,
|
||||
types.MethodType,
|
||||
types.ModuleType)
|
||||
if not compat.PYTHON3: # pragma: nocover
|
||||
# Python 2 old style classes
|
||||
CONTAINER_TYPES = tuple(list(CONTAINER_TYPES) + [types.ClassType])
|
||||
PYDOC_TYPES = tuple(list(PYDOC_TYPES) + [types.ClassType])
|
||||
|
||||
|
||||
def get_pydoc_completions(modulename):
|
||||
"""Get possible completions for modulename for pydoc.
|
||||
|
||||
Returns a list of possible values to be passed to pydoc.
|
||||
|
||||
"""
|
||||
modulename = compat.ensure_not_unicode(modulename)
|
||||
modulename = modulename.rstrip(".")
|
||||
if modulename == "":
|
||||
return sorted(get_modules())
|
||||
candidates = get_completions(modulename)
|
||||
if candidates:
|
||||
return sorted(candidates)
|
||||
needle = modulename
|
||||
if "." in needle:
|
||||
modulename, part = needle.rsplit(".", 1)
|
||||
candidates = get_completions(modulename)
|
||||
else:
|
||||
candidates = get_modules()
|
||||
return sorted(candidate for candidate in candidates
|
||||
if candidate.startswith(needle))
|
||||
|
||||
|
||||
def get_completions(modulename):
|
||||
modules = set("{0}.{1}".format(modulename, module)
|
||||
for module in get_modules(modulename))
|
||||
|
||||
try:
|
||||
module, name = resolve(modulename)
|
||||
except ImportError:
|
||||
return modules
|
||||
if isinstance(module, CONTAINER_TYPES):
|
||||
modules.update("{0}.{1}".format(modulename, name)
|
||||
for name in dir(module)
|
||||
if not name.startswith("_") and
|
||||
isinstance(getattr(module, name),
|
||||
PYDOC_TYPES))
|
||||
return modules
|
||||
|
||||
|
||||
def get_modules(modulename=None):
|
||||
"""Return a list of modules and packages under modulename.
|
||||
|
||||
If modulename is not given, return a list of all top level modules
|
||||
and packages.
|
||||
|
||||
"""
|
||||
modulename = compat.ensure_not_unicode(modulename)
|
||||
if not modulename:
|
||||
try:
|
||||
return ([modname for (importer, modname, ispkg)
|
||||
in iter_modules()
|
||||
if not modname.startswith("_")] +
|
||||
list(sys.builtin_module_names))
|
||||
except OSError:
|
||||
# Bug in Python 2.6, see #275
|
||||
return list(sys.builtin_module_names)
|
||||
try:
|
||||
module = safeimport(modulename)
|
||||
except ErrorDuringImport:
|
||||
return []
|
||||
if module is None:
|
||||
return []
|
||||
if hasattr(module, "__path__"):
|
||||
return [modname for (importer, modname, ispkg)
|
||||
in iter_modules(module.__path__)
|
||||
if not modname.startswith("_")]
|
||||
return []
|
Binary file not shown.
|
@ -0,0 +1,381 @@
|
|||
"""Refactoring methods for elpy.
|
||||
|
||||
This interfaces directly with rope, regardless of the backend used,
|
||||
because the other backends don't really offer refactoring choices.
|
||||
Once Jedi is similarly featureful as Rope we can try and offer both.
|
||||
|
||||
|
||||
# Too complex:
|
||||
|
||||
- Restructure: Interesting, but too complex, and needs deep Rope
|
||||
knowledge to do well.
|
||||
|
||||
- ChangeSignature: Slightly less complex interface, but still to
|
||||
complex, requiring a large effort for the benefit.
|
||||
|
||||
|
||||
# Too useless:
|
||||
|
||||
I could not get these to work in any useful fashion. I might be doing
|
||||
something wrong.
|
||||
|
||||
- ExtractVariable does not replace the code extracted with the
|
||||
variable, making it a glorified copy&paste function. Emacs can do
|
||||
better than this interface by itself.
|
||||
|
||||
- EncapsulateField: Getter/setter methods are outdated, this should be
|
||||
using properties.
|
||||
|
||||
- IntroduceFactory: Inserts a trivial method to the current class.
|
||||
Cute.
|
||||
|
||||
- IntroduceParameter: Introduces a parameter correctly, but does not
|
||||
replace the old code with the parameter. So it just edits the
|
||||
argument list and adds a shiny default.
|
||||
|
||||
- LocalToField: Seems to just add "self." in front of all occurrences
|
||||
of a variable in the local scope.
|
||||
|
||||
- MethodObject: This turns the current method into a callable
|
||||
class/object. Not sure what that would be good for.
|
||||
|
||||
|
||||
# Can't even get to work:
|
||||
|
||||
- ImportOrganizer expand_star_imports, handle_long_imports,
|
||||
relatives_to_absolutes: Seem not to do anything.
|
||||
|
||||
- create_move: I was not able to figure out what it would like to see
|
||||
as its attrib argument.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from elpy.rpc import Fault
|
||||
|
||||
try:
|
||||
from rope.base.exceptions import RefactoringError
|
||||
from rope.base.project import Project
|
||||
from rope.base.libutils import path_to_resource
|
||||
from rope.base import change as rope_change
|
||||
from rope.base import worder
|
||||
from rope.refactor.importutils import ImportOrganizer
|
||||
from rope.refactor.topackage import ModuleToPackage
|
||||
from rope.refactor.rename import Rename
|
||||
from rope.refactor.move import create_move
|
||||
from rope.refactor.inline import create_inline
|
||||
from rope.refactor.extract import ExtractMethod
|
||||
from rope.refactor.usefunction import UseFunction
|
||||
ROPE_AVAILABLE = True
|
||||
except ImportError:
|
||||
ROPE_AVAILABLE = False
|
||||
|
||||
|
||||
def options(description, **kwargs):
|
||||
"""Decorator to set some options on a method."""
|
||||
def set_notes(function):
|
||||
function.refactor_notes = {'name': function.__name__,
|
||||
'category': "Miscellaneous",
|
||||
'description': description,
|
||||
'doc': getattr(function, '__doc__',
|
||||
''),
|
||||
'args': []}
|
||||
function.refactor_notes.update(kwargs)
|
||||
return function
|
||||
return set_notes
|
||||
|
||||
|
||||
class Refactor(object):
|
||||
"""The main refactoring interface.
|
||||
|
||||
Once initialized, the first call should be to get_refactor_options
|
||||
to get a list of refactoring options at a given position. The
|
||||
returned value will also list any additional options required.
|
||||
|
||||
Once you picked one, you can call get_changes to get the actual
|
||||
refactoring changes.
|
||||
|
||||
"""
|
||||
def __init__(self, project_root, filename):
|
||||
self.project_root = project_root
|
||||
if not ROPE_AVAILABLE:
|
||||
raise Fault('rope not installed, cannot refactor code.',
|
||||
code=400)
|
||||
if not os.path.exists(project_root):
|
||||
raise Fault(
|
||||
"cannot do refactoring without a local project root",
|
||||
code=400
|
||||
)
|
||||
self.project = Project(project_root, ropefolder=None)
|
||||
self.resource = path_to_resource(self.project, filename)
|
||||
|
||||
def get_refactor_options(self, start, end=None):
|
||||
"""Return a list of options for refactoring at the given position.
|
||||
|
||||
If `end` is also given, refactoring on a region is assumed.
|
||||
|
||||
Each option is a dictionary of key/value pairs. The value of
|
||||
the key 'name' is the one to be used for get_changes.
|
||||
|
||||
The key 'args' contains a list of additional arguments
|
||||
required for get_changes.
|
||||
|
||||
"""
|
||||
result = []
|
||||
for symbol in dir(self):
|
||||
if not symbol.startswith("refactor_"):
|
||||
continue
|
||||
method = getattr(self, symbol)
|
||||
if not method.refactor_notes.get('available', True):
|
||||
continue
|
||||
category = method.refactor_notes['category']
|
||||
if end is not None and category != 'Region':
|
||||
continue
|
||||
if end is None and category == 'Region':
|
||||
continue
|
||||
is_on_symbol = self._is_on_symbol(start)
|
||||
if not is_on_symbol and category in ('Symbol', 'Method'):
|
||||
continue
|
||||
requires_import = method.refactor_notes.get('only_on_imports',
|
||||
False)
|
||||
if requires_import and not self._is_on_import_statement(start):
|
||||
continue
|
||||
result.append(method.refactor_notes)
|
||||
return result
|
||||
|
||||
def _is_on_import_statement(self, offset):
|
||||
"Does this offset point to an import statement?"
|
||||
data = self.resource.read()
|
||||
bol = data.rfind("\n", 0, offset) + 1
|
||||
eol = data.find("\n", 0, bol)
|
||||
if eol == -1:
|
||||
eol = len(data)
|
||||
line = data[bol:eol]
|
||||
line = line.strip()
|
||||
if line.startswith("import ") or line.startswith("from "):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _is_on_symbol(self, offset):
|
||||
"Is this offset on a symbol?"
|
||||
if not ROPE_AVAILABLE:
|
||||
return False
|
||||
data = self.resource.read()
|
||||
if offset >= len(data):
|
||||
return False
|
||||
if data[offset] != '_' and not data[offset].isalnum():
|
||||
return False
|
||||
word = worder.get_name_at(self.resource, offset)
|
||||
if word:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_changes(self, name, *args):
|
||||
"""Return a list of changes for the named refactoring action.
|
||||
|
||||
Changes are dictionaries describing a single action to be
|
||||
taken for the refactoring to be successful.
|
||||
|
||||
A change has an action and possibly a type. In the description
|
||||
below, the action is before the slash and the type after it.
|
||||
|
||||
change: Change file contents
|
||||
- file: The path to the file to change
|
||||
- contents: The new contents for the file
|
||||
- Diff: A unified diff showing the changes introduced
|
||||
|
||||
create/file: Create a new file
|
||||
- file: The file to create
|
||||
|
||||
create/directory: Create a new directory
|
||||
- path: The directory to create
|
||||
|
||||
move/file: Rename a file
|
||||
- source: The path to the source file
|
||||
- destination: The path to the destination file name
|
||||
|
||||
move/directory: Rename a directory
|
||||
- source: The path to the source directory
|
||||
- destination: The path to the destination directory name
|
||||
|
||||
delete/file: Delete a file
|
||||
- file: The file to delete
|
||||
|
||||
delete/directory: Delete a directory
|
||||
- path: The directory to delete
|
||||
|
||||
"""
|
||||
if not name.startswith("refactor_"):
|
||||
raise ValueError("Bad refactoring name {0}".format(name))
|
||||
method = getattr(self, name)
|
||||
if not method.refactor_notes.get('available', True):
|
||||
raise RuntimeError("Method not available")
|
||||
return method(*args)
|
||||
|
||||
@options("Convert from x import y to import x.y as y", category="Imports",
|
||||
args=[("offset", "offset", None)],
|
||||
only_on_imports=True,
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_froms_to_imports(self, offset):
|
||||
"""Converting imports of the form "from ..." to "import ..."."""
|
||||
refactor = ImportOrganizer(self.project)
|
||||
changes = refactor.froms_to_imports(self.resource, offset)
|
||||
return translate_changes(changes)
|
||||
|
||||
@options("Reorganize and clean up", category="Imports",
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_organize_imports(self):
|
||||
"""Clean up and organize imports."""
|
||||
refactor = ImportOrganizer(self.project)
|
||||
changes = refactor.organize_imports(self.resource)
|
||||
return translate_changes(changes)
|
||||
|
||||
@options("Convert the current module into a package", category="Module",
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_module_to_package(self):
|
||||
"""Convert the current module into a package."""
|
||||
refactor = ModuleToPackage(self.project, self.resource)
|
||||
return self._get_changes(refactor)
|
||||
|
||||
@options("Rename symbol at point", category="Symbol",
|
||||
args=[("offset", "offset", None),
|
||||
("new_name", "string", "Rename to: "),
|
||||
("in_hierarchy", "boolean",
|
||||
"Rename in super-/subclasses as well? "),
|
||||
("docs", "boolean",
|
||||
"Replace occurences in docs and strings? ")
|
||||
],
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_rename_at_point(self, offset, new_name, in_hierarchy, docs):
|
||||
"""Rename the symbol at point."""
|
||||
try:
|
||||
refactor = Rename(self.project, self.resource, offset)
|
||||
except RefactoringError as e:
|
||||
raise Fault(str(e), code=400)
|
||||
return self._get_changes(refactor, new_name,
|
||||
in_hierarchy=in_hierarchy, docs=docs)
|
||||
|
||||
@options("Rename current module", category="Module",
|
||||
args=[("new_name", "string", "Rename to: ")],
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_rename_current_module(self, new_name):
|
||||
"""Rename the current module."""
|
||||
refactor = Rename(self.project, self.resource, None)
|
||||
return self._get_changes(refactor, new_name)
|
||||
|
||||
@options("Move the current module to a different package",
|
||||
category="Module",
|
||||
args=[("new_name", "directory", "Destination package: ")],
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_move_module(self, new_name):
|
||||
"""Move the current module."""
|
||||
refactor = create_move(self.project, self.resource)
|
||||
resource = path_to_resource(self.project, new_name)
|
||||
return self._get_changes(refactor, resource)
|
||||
|
||||
@options("Inline function call at point", category="Symbol",
|
||||
args=[("offset", "offset", None),
|
||||
("only_this", "boolean", "Only this occurrence? ")],
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_create_inline(self, offset, only_this):
|
||||
"""Inline the function call at point."""
|
||||
refactor = create_inline(self.project, self.resource, offset)
|
||||
if only_this:
|
||||
return self._get_changes(refactor, remove=False, only_current=True)
|
||||
else:
|
||||
return self._get_changes(refactor, remove=True, only_current=False)
|
||||
|
||||
@options("Extract current region as a method", category="Region",
|
||||
args=[("start", "start_offset", None),
|
||||
("end", "end_offset", None),
|
||||
("name", "string", "Method name: "),
|
||||
("make_global", "boolean", "Create global method? ")],
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_extract_method(self, start, end, name,
|
||||
make_global):
|
||||
"""Extract region as a method."""
|
||||
refactor = ExtractMethod(self.project, self.resource, start, end)
|
||||
return self._get_changes(
|
||||
refactor, name, similar=True, global_=make_global
|
||||
)
|
||||
|
||||
@options("Use the function at point wherever possible", category="Method",
|
||||
args=[("offset", "offset", None)],
|
||||
available=ROPE_AVAILABLE)
|
||||
def refactor_use_function(self, offset):
|
||||
"""Use the function at point wherever possible."""
|
||||
try:
|
||||
refactor = UseFunction(self.project, self.resource, offset)
|
||||
except RefactoringError as e:
|
||||
raise Fault(
|
||||
'Refactoring error: {}'.format(e),
|
||||
code=400
|
||||
)
|
||||
return self._get_changes(refactor)
|
||||
|
||||
def _get_changes(self, refactor, *args, **kwargs):
|
||||
try:
|
||||
changes = refactor.get_changes(*args, **kwargs)
|
||||
except Exception as e:
|
||||
raise Fault("Error during refactoring: {}".format(e),
|
||||
code=400)
|
||||
return translate_changes(changes)
|
||||
|
||||
|
||||
def translate_changes(initial_change):
|
||||
"""Translate rope.base.change.Change instances to dictionaries.
|
||||
|
||||
See Refactor.get_changes for an explanation of the resulting
|
||||
dictionary.
|
||||
|
||||
"""
|
||||
agenda = [initial_change]
|
||||
result = []
|
||||
while agenda:
|
||||
change = agenda.pop(0)
|
||||
if isinstance(change, rope_change.ChangeSet):
|
||||
agenda.extend(change.changes)
|
||||
elif isinstance(change, rope_change.ChangeContents):
|
||||
result.append({'action': 'change',
|
||||
'file': change.resource.real_path,
|
||||
'contents': change.new_contents,
|
||||
'diff': change.get_description()})
|
||||
elif isinstance(change, rope_change.CreateFile):
|
||||
result.append({'action': 'create',
|
||||
'type': 'file',
|
||||
'file': change.resource.real_path})
|
||||
elif isinstance(change, rope_change.CreateFolder):
|
||||
result.append({'action': 'create',
|
||||
'type': 'directory',
|
||||
'path': change.resource.real_path})
|
||||
elif isinstance(change, rope_change.MoveResource):
|
||||
result.append({'action': 'move',
|
||||
'type': ('directory'
|
||||
if change.new_resource.is_folder()
|
||||
else 'file'),
|
||||
'source': change.resource.real_path,
|
||||
'destination': change.new_resource.real_path})
|
||||
elif isinstance(change, rope_change.RemoveResource):
|
||||
if change.resource.is_folder():
|
||||
result.append({'action': 'delete',
|
||||
'type': 'directory',
|
||||
'path': change.resource.real_path})
|
||||
else:
|
||||
result.append({'action': 'delete',
|
||||
'type': 'file',
|
||||
'file': change.resource.real_path})
|
||||
return result
|
||||
|
||||
|
||||
class FakeResource(object):
|
||||
"""A fake resource in case Rope is absence."""
|
||||
|
||||
def __init__(self, filename):
|
||||
self.real_path = filename
|
||||
|
||||
def read(self):
|
||||
with open(self.real_path) as f:
|
||||
return f.read()
|
|
@ -0,0 +1,151 @@
|
|||
"""A simple JSON-RPC-like server.
|
||||
|
||||
The server will read and write lines of JSON-encoded method calls and
|
||||
responses.
|
||||
|
||||
See the documentation of the JSONRPCServer class for further details.
|
||||
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
|
||||
class JSONRPCServer(object):
|
||||
"""Simple JSON-RPC-like server.
|
||||
|
||||
This class will read single-line JSON expressions from stdin,
|
||||
decode them, and pass them to a handler. Return values from the
|
||||
handler will be JSON-encoded and written to stdout.
|
||||
|
||||
To implement a handler, you need to subclass this class and add
|
||||
methods starting with "rpc_". Methods then will be found.
|
||||
|
||||
Method calls should be encoded like this:
|
||||
|
||||
{"id": 23, "method": "method_name", "params": ["foo", "bar"]}
|
||||
|
||||
This will call self.rpc_method("foo", "bar").
|
||||
|
||||
Responses will be encoded like this:
|
||||
|
||||
{"id": 23, "result": "foo"}
|
||||
|
||||
Errors will be encoded like this:
|
||||
|
||||
{"id": 23, "error": "Simple error message"}
|
||||
|
||||
See http://www.jsonrpc.org/ for the inspiration of the protocol.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, stdin=None, stdout=None):
|
||||
"""Return a new JSON-RPC server object.
|
||||
|
||||
It will read lines of JSON data from stdin, and write the
|
||||
responses to stdout.
|
||||
|
||||
"""
|
||||
if stdin is None:
|
||||
self.stdin = sys.stdin
|
||||
else:
|
||||
self.stdin = stdin
|
||||
if stdout is None:
|
||||
self.stdout = sys.stdout
|
||||
else:
|
||||
self.stdout = stdout
|
||||
|
||||
def read_json(self):
|
||||
"""Read a single line and decode it as JSON.
|
||||
|
||||
Can raise an EOFError() when the input source was closed.
|
||||
|
||||
"""
|
||||
line = self.stdin.readline()
|
||||
if line == '':
|
||||
raise EOFError()
|
||||
return json.loads(line)
|
||||
|
||||
def write_json(self, **kwargs):
|
||||
"""Write an JSON object on a single line.
|
||||
|
||||
The keyword arguments are interpreted as a single JSON object.
|
||||
It's not possible with this method to write non-objects.
|
||||
|
||||
"""
|
||||
self.stdout.write(json.dumps(kwargs) + "\n")
|
||||
self.stdout.flush()
|
||||
|
||||
def handle_request(self):
|
||||
"""Handle a single JSON-RPC request.
|
||||
|
||||
Read a request, call the appropriate handler method, and
|
||||
return the encoded result. Errors in the handler method are
|
||||
caught and encoded as error objects. Errors in the decoding
|
||||
phase are not caught, as we can not respond with an error
|
||||
response to them.
|
||||
|
||||
"""
|
||||
request = self.read_json()
|
||||
if 'method' not in request:
|
||||
raise ValueError("Received a bad request: {0}"
|
||||
.format(request))
|
||||
method_name = request['method']
|
||||
request_id = request.get('id', None)
|
||||
params = request.get('params') or []
|
||||
try:
|
||||
method = getattr(self, "rpc_" + method_name, None)
|
||||
if method is not None:
|
||||
result = method(*params)
|
||||
else:
|
||||
result = self.handle(method_name, params)
|
||||
if request_id is not None:
|
||||
self.write_json(result=result,
|
||||
id=request_id)
|
||||
except Fault as fault:
|
||||
error = {"message": fault.message,
|
||||
"code": fault.code}
|
||||
if fault.data is not None:
|
||||
error["data"] = fault.data
|
||||
self.write_json(error=error, id=request_id)
|
||||
except Exception as e:
|
||||
error = {"message": str(e),
|
||||
"code": 500,
|
||||
"data": {"traceback": traceback.format_exc()}}
|
||||
self.write_json(error=error, id=request_id)
|
||||
|
||||
def handle(self, method_name, args):
|
||||
"""Handle the call to method_name.
|
||||
|
||||
You should overwrite this method in a subclass.
|
||||
"""
|
||||
raise Fault("Unknown method {0}".format(method_name))
|
||||
|
||||
def serve_forever(self):
|
||||
"""Serve requests forever.
|
||||
|
||||
Errors are not caught, so this is a slight misnomer.
|
||||
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
self.handle_request()
|
||||
except (KeyboardInterrupt, EOFError, SystemExit):
|
||||
break
|
||||
|
||||
|
||||
class Fault(Exception):
|
||||
"""RPC Fault instances.
|
||||
|
||||
code defines the severity of the warning.
|
||||
|
||||
2xx: Normal behavior lead to end of operation, i.e. a warning
|
||||
4xx: An expected error occurred
|
||||
5xx: An unexpected error occurred (usually includes a traceback)
|
||||
"""
|
||||
def __init__(self, message, code=500, data=None):
|
||||
super(Fault, self).__init__(message)
|
||||
self.message = message
|
||||
self.code = code
|
||||
self.data = data
|
Binary file not shown.
|
@ -0,0 +1,263 @@
|
|||
"""Method implementations for the Elpy JSON-RPC server.
|
||||
|
||||
This file implements the methods exported by the JSON-RPC server. It
|
||||
handles backend selection and passes methods on to the selected
|
||||
backend.
|
||||
|
||||
"""
|
||||
import io
|
||||
import os
|
||||
import pydoc
|
||||
|
||||
from elpy.pydocutils import get_pydoc_completions
|
||||
from elpy.rpc import JSONRPCServer, Fault
|
||||
from elpy.auto_pep8 import fix_code
|
||||
from elpy.yapfutil import fix_code as fix_code_with_yapf
|
||||
from elpy.blackutil import fix_code as fix_code_with_black
|
||||
|
||||
|
||||
try:
|
||||
from elpy import jedibackend
|
||||
except ImportError: # pragma: no cover
|
||||
jedibackend = None
|
||||
|
||||
|
||||
class ElpyRPCServer(JSONRPCServer):
|
||||
"""The RPC server for elpy.
|
||||
|
||||
See the rpc_* methods for exported method documentation.
|
||||
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ElpyRPCServer, self).__init__(*args, **kwargs)
|
||||
self.backend = None
|
||||
self.project_root = None
|
||||
|
||||
def _call_backend(self, method, default, *args, **kwargs):
|
||||
"""Call the backend method with args.
|
||||
|
||||
If there is currently no backend, return default."""
|
||||
meth = getattr(self.backend, method, None)
|
||||
if meth is None:
|
||||
return default
|
||||
else:
|
||||
return meth(*args, **kwargs)
|
||||
|
||||
def rpc_echo(self, *args):
|
||||
"""Return the arguments.
|
||||
|
||||
This is a simple test method to see if the protocol is
|
||||
working.
|
||||
|
||||
"""
|
||||
return args
|
||||
|
||||
def rpc_init(self, options):
|
||||
self.project_root = options["project_root"]
|
||||
|
||||
if jedibackend:
|
||||
self.backend = jedibackend.JediBackend(self.project_root)
|
||||
else:
|
||||
self.backend = None
|
||||
|
||||
return {
|
||||
'jedi_available': (self.backend is not None)
|
||||
}
|
||||
|
||||
def rpc_get_calltip(self, filename, source, offset):
|
||||
"""Get the calltip for the function at the offset.
|
||||
|
||||
"""
|
||||
return self._call_backend("rpc_get_calltip", None, filename,
|
||||
get_source(source), offset)
|
||||
|
||||
def rpc_get_completions(self, filename, source, offset):
|
||||
"""Get a list of completion candidates for the symbol at offset.
|
||||
|
||||
"""
|
||||
results = self._call_backend("rpc_get_completions", [], filename,
|
||||
get_source(source), offset)
|
||||
# Uniquify by name
|
||||
results = list(dict((res['name'], res) for res in results)
|
||||
.values())
|
||||
results.sort(key=lambda cand: _pysymbol_key(cand["name"]))
|
||||
return results
|
||||
|
||||
def rpc_get_completion_docstring(self, completion):
|
||||
"""Return documentation for a previously returned completion.
|
||||
|
||||
"""
|
||||
return self._call_backend("rpc_get_completion_docstring",
|
||||
None, completion)
|
||||
|
||||
def rpc_get_completion_location(self, completion):
|
||||
"""Return the location for a previously returned completion.
|
||||
|
||||
This returns a list of [file name, line number].
|
||||
|
||||
"""
|
||||
return self._call_backend("rpc_get_completion_location", None,
|
||||
completion)
|
||||
|
||||
def rpc_get_definition(self, filename, source, offset):
|
||||
"""Get the location of the definition for the symbol at the offset.
|
||||
|
||||
"""
|
||||
return self._call_backend("rpc_get_definition", None, filename,
|
||||
get_source(source), offset)
|
||||
|
||||
def rpc_get_assignment(self, filename, source, offset):
|
||||
"""Get the location of the assignment for the symbol at the offset.
|
||||
|
||||
"""
|
||||
return self._call_backend("rpc_get_assignment", None, filename,
|
||||
get_source(source), offset)
|
||||
|
||||
def rpc_get_docstring(self, filename, source, offset):
|
||||
"""Get the docstring for the symbol at the offset.
|
||||
|
||||
"""
|
||||
return self._call_backend("rpc_get_docstring", None, filename,
|
||||
get_source(source), offset)
|
||||
|
||||
def rpc_get_pydoc_completions(self, name=None):
|
||||
"""Return a list of possible strings to pass to pydoc.
|
||||
|
||||
If name is given, the strings are under name. If not, top
|
||||
level modules are returned.
|
||||
|
||||
"""
|
||||
return get_pydoc_completions(name)
|
||||
|
||||
def rpc_get_pydoc_documentation(self, symbol):
|
||||
"""Get the Pydoc documentation for the given symbol.
|
||||
|
||||
Uses pydoc and can return a string with backspace characters
|
||||
for bold highlighting.
|
||||
|
||||
"""
|
||||
try:
|
||||
docstring = pydoc.render_doc(str(symbol),
|
||||
"Elpy Pydoc Documentation for %s",
|
||||
False)
|
||||
except (ImportError, pydoc.ErrorDuringImport):
|
||||
return None
|
||||
else:
|
||||
if isinstance(docstring, bytes):
|
||||
docstring = docstring.decode("utf-8", "replace")
|
||||
return docstring
|
||||
|
||||
def rpc_get_refactor_options(self, filename, start, end=None):
|
||||
"""Return a list of possible refactoring options.
|
||||
|
||||
This list will be filtered depending on whether it's
|
||||
applicable at the point START and possibly the region between
|
||||
START and END.
|
||||
|
||||
"""
|
||||
try:
|
||||
from elpy import refactor
|
||||
except:
|
||||
raise ImportError("Rope not installed, refactorings unavailable")
|
||||
ref = refactor.Refactor(self.project_root, filename)
|
||||
return ref.get_refactor_options(start, end)
|
||||
|
||||
def rpc_refactor(self, filename, method, args):
|
||||
"""Return a list of changes from the refactoring action.
|
||||
|
||||
A change is a dictionary describing the change. See
|
||||
elpy.refactor.translate_changes for a description.
|
||||
|
||||
"""
|
||||
try:
|
||||
from elpy import refactor
|
||||
except:
|
||||
raise ImportError("Rope not installed, refactorings unavailable")
|
||||
if args is None:
|
||||
args = ()
|
||||
ref = refactor.Refactor(self.project_root, filename)
|
||||
return ref.get_changes(method, *args)
|
||||
|
||||
def rpc_get_usages(self, filename, source, offset):
|
||||
"""Get usages for the symbol at point.
|
||||
|
||||
"""
|
||||
source = get_source(source)
|
||||
if hasattr(self.backend, "rpc_get_usages"):
|
||||
return self.backend.rpc_get_usages(filename, source, offset)
|
||||
else:
|
||||
raise Fault("get_usages not implemented by current backend",
|
||||
code=400)
|
||||
|
||||
def rpc_get_names(self, filename, source, offset):
|
||||
"""Get all possible names
|
||||
|
||||
"""
|
||||
source = get_source(source)
|
||||
if hasattr(self.backend, "rpc_get_names"):
|
||||
return self.backend.rpc_get_names(filename, source, offset)
|
||||
else:
|
||||
raise Fault("get_names not implemented by current backend",
|
||||
code=400)
|
||||
|
||||
def rpc_fix_code(self, source, directory):
|
||||
"""Formats Python code to conform to the PEP 8 style guide.
|
||||
|
||||
"""
|
||||
source = get_source(source)
|
||||
return fix_code(source, directory)
|
||||
|
||||
def rpc_fix_code_with_yapf(self, source, directory):
|
||||
"""Formats Python code to conform to the PEP 8 style guide.
|
||||
|
||||
"""
|
||||
source = get_source(source)
|
||||
return fix_code_with_yapf(source, directory)
|
||||
|
||||
def rpc_fix_code_with_black(self, source, directory):
|
||||
"""Formats Python code to conform to the PEP 8 style guide.
|
||||
|
||||
"""
|
||||
source = get_source(source)
|
||||
return fix_code_with_black(source, directory)
|
||||
|
||||
|
||||
def get_source(fileobj):
|
||||
"""Translate fileobj into file contents.
|
||||
|
||||
fileobj is either a string or a dict. If it's a string, that's the
|
||||
file contents. If it's a string, then the filename key contains
|
||||
the name of the file whose contents we are to use.
|
||||
|
||||
If the dict contains a true value for the key delete_after_use,
|
||||
the file should be deleted once read.
|
||||
|
||||
"""
|
||||
if not isinstance(fileobj, dict):
|
||||
return fileobj
|
||||
else:
|
||||
try:
|
||||
with io.open(fileobj["filename"], encoding="utf-8",
|
||||
errors="ignore") as f:
|
||||
return f.read()
|
||||
finally:
|
||||
if fileobj.get('delete_after_use'):
|
||||
try:
|
||||
os.remove(fileobj["filename"])
|
||||
except: # pragma: no cover
|
||||
pass
|
||||
|
||||
|
||||
def _pysymbol_key(name):
|
||||
"""Return a sortable key index for name.
|
||||
|
||||
Sorting is case-insensitive, with the first underscore counting as
|
||||
worse than any character, but subsequent underscores do not. This
|
||||
means that dunder symbols (like __init__) are sorted after symbols
|
||||
that start with an alphabetic character, but before those that
|
||||
start with only a single underscore.
|
||||
|
||||
"""
|
||||
if name.startswith("_"):
|
||||
name = "~" + name[1:]
|
||||
return name.lower()
|
Binary file not shown.
|
@ -0,0 +1,8 @@
|
|||
"""Unit tests for elpy."""
|
||||
|
||||
try:
|
||||
import unittest2
|
||||
import sys
|
||||
sys.modules['unittest'] = unittest2
|
||||
except:
|
||||
pass
|
|
@ -0,0 +1,18 @@
|
|||
"""Python 2/3 compatibility definitions.
|
||||
|
||||
These are used by the rest of Elpy to keep compatibility definitions
|
||||
in one place.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
PYTHON3 = True
|
||||
import builtins
|
||||
from io import StringIO
|
||||
else:
|
||||
PYTHON3 = False
|
||||
import __builtin__ as builtins # noqa
|
||||
from StringIO import StringIO # noqa
|
|
@ -0,0 +1,947 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""Support classes and functions for the elpy test code.
|
||||
|
||||
Elpy uses a bit of a peculiar test setup to avoid redundancy. For the
|
||||
tests of the two backends, we provide generic test cases for generic
|
||||
tests and for specific callback tests.
|
||||
|
||||
These mixins can be included in the actual test classes. We can't add
|
||||
these tests to a BackendTestCase subclass directly because the test
|
||||
discovery would find them there and try to run them, which would fail.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from elpy.tests import compat
|
||||
|
||||
|
||||
class BackendTestCase(unittest.TestCase):
|
||||
"""Base class for backend tests.
|
||||
|
||||
This class sets up a project root directory and provides an easy
|
||||
way to create files within the project root.
|
||||
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Create the project root and make sure it gets cleaned up."""
|
||||
super(BackendTestCase, self).setUp()
|
||||
self.project_root = tempfile.mkdtemp(prefix="elpy-test")
|
||||
self.addCleanup(shutil.rmtree, self.project_root, True)
|
||||
|
||||
def project_file(self, relname, contents):
|
||||
"""Create a file named relname within the project root.
|
||||
|
||||
Write contents into that file.
|
||||
|
||||
"""
|
||||
full_name = os.path.join(self.project_root, relname)
|
||||
try:
|
||||
os.makedirs(os.path.dirname(full_name))
|
||||
except OSError:
|
||||
pass
|
||||
if compat.PYTHON3:
|
||||
fobj = open(full_name, "w", encoding="utf-8")
|
||||
else:
|
||||
fobj = open(full_name, "w")
|
||||
with fobj as f:
|
||||
f.write(contents)
|
||||
return full_name
|
||||
|
||||
|
||||
class GenericRPCTests(object):
|
||||
"""Generic RPC test methods.
|
||||
|
||||
This is a mixin to add tests that should be run for all RPC
|
||||
methods that follow the generic (filename, source, offset) calling
|
||||
conventions.
|
||||
|
||||
"""
|
||||
METHOD = None
|
||||
|
||||
def rpc(self, filename, source, offset):
|
||||
method = getattr(self.backend, self.METHOD)
|
||||
return method(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_on_inexisting_file(self):
|
||||
filename = self.project_root + "/doesnotexist.py"
|
||||
self.rpc(filename, "", 0)
|
||||
|
||||
def test_should_not_fail_on_empty_file(self):
|
||||
filename = self.project_file("test.py", "")
|
||||
self.rpc(filename, "", 0)
|
||||
|
||||
def test_should_not_fail_if_file_is_none(self):
|
||||
self.rpc(None, "", 0)
|
||||
|
||||
def test_should_not_fail_for_module_syntax_errors(self):
|
||||
source, offset = source_and_offset(
|
||||
"class Foo(object):\n"
|
||||
" def bar(self):\n"
|
||||
" foo(_|_"
|
||||
" bar("
|
||||
"\n"
|
||||
" def a(self):\n"
|
||||
" pass\n"
|
||||
"\n"
|
||||
" def b(self):\n"
|
||||
" pass\n"
|
||||
"\n"
|
||||
" def b(self):\n"
|
||||
" pass\n"
|
||||
"\n"
|
||||
" def b(self):\n"
|
||||
" pass\n"
|
||||
"\n"
|
||||
" def b(self):\n"
|
||||
" pass\n"
|
||||
"\n"
|
||||
" def b(self):\n"
|
||||
" pass\n"
|
||||
)
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_bad_indentation(self):
|
||||
source, offset = source_and_offset(
|
||||
"def foo():\n"
|
||||
" print(23)_|_\n"
|
||||
" print(17)\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
@unittest.skipIf((3, 3) <= sys.version_info < (3, 4),
|
||||
"Bug in jedi for Python 3.3")
|
||||
def test_should_not_fail_for_relative_import(self):
|
||||
source, offset = source_and_offset(
|
||||
"from .. import foo_|_"
|
||||
)
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_on_keyword(self):
|
||||
source, offset = source_and_offset(
|
||||
"_|_try:\n"
|
||||
" pass\n"
|
||||
"except:\n"
|
||||
" pass\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_with_bad_encoding(self):
|
||||
source, offset = source_and_offset(
|
||||
u'# coding: utf-8X_|_\n'
|
||||
)
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_with_form_feed_characters(self):
|
||||
# Bug in Jedi: jedi#424
|
||||
source, offset = source_and_offset(
|
||||
"\f\n"
|
||||
"class Test(object):_|_\n"
|
||||
" pass"
|
||||
)
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_dictionaries_in_weird_places(self):
|
||||
# Bug in Jedi: jedi#417
|
||||
source, offset = source_and_offset(
|
||||
"import json\n"
|
||||
"\n"
|
||||
"def foo():\n"
|
||||
" json.loads(_|_\n"
|
||||
"\n"
|
||||
" json.load.return_value = {'foo': [],\n"
|
||||
" 'bar': True}\n"
|
||||
"\n"
|
||||
" c = Foo()\n"
|
||||
)
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_break_with_binary_characters_in_docstring(self):
|
||||
# Bug in Jedi: jedi#427
|
||||
template = '''\
|
||||
class Foo(object):
|
||||
def __init__(self):
|
||||
"""
|
||||
COMMUNITY instance that this conversion belongs to.
|
||||
DISPERSY_VERSION is the dispersy conversion identifier (on the wire version; must be one byte).
|
||||
COMMUNIY_VERSION is the community conversion identifier (on the wire version; must be one byte).
|
||||
|
||||
COMMUNIY_VERSION may not be '\\x00' or '\\xff'. '\\x00' is used by the DefaultConversion until
|
||||
a proper conversion instance can be made for the Community. '\\xff' is reserved for when
|
||||
more than one byte is needed as a version indicator.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
x = Foo()
|
||||
x._|_
|
||||
'''
|
||||
source, offset = source_and_offset(template)
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_def_without_name(self):
|
||||
# Bug jedi#429
|
||||
source, offset = source_and_offset(
|
||||
"def_|_():\n"
|
||||
" if True:\n"
|
||||
" return True\n"
|
||||
" else:\n"
|
||||
" return False\n"
|
||||
)
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_on_lambda(self):
|
||||
# Bug #272 / jedi#431, jedi#572
|
||||
source, offset = source_and_offset(
|
||||
"map(lambda_|_"
|
||||
)
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_on_literals(self):
|
||||
# Bug #314, #344 / jedi#466
|
||||
source = u'lit = u"""\\\n# -*- coding: utf-8 -*-\n"""\n'
|
||||
offset = 0
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_with_args_as_args(self):
|
||||
# Bug #347 in rope_py3k
|
||||
source, offset = source_and_offset(
|
||||
"def my_function(*args):\n"
|
||||
" ret_|_"
|
||||
)
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_unicode_chars_in_string(self):
|
||||
# Bug #358 / jedi#482
|
||||
source = '''\
|
||||
# coding: utf-8
|
||||
|
||||
logging.info(u"Saving «{}»...".format(title))
|
||||
requests.get(u"https://web.archive.org/save/{}".format(url))
|
||||
'''
|
||||
offset = 57
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_bad_escape_sequence(self):
|
||||
# Bug #360 / jedi#485
|
||||
source = r"v = '\x'"
|
||||
offset = 8
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_coding_declarations_in_strings(self):
|
||||
# Bug #314 / jedi#465 / python#22221
|
||||
source = u'lit = """\\\n# -*- coding: utf-8 -*-\n"""'
|
||||
offset = 8
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_if_root_vanishes(self):
|
||||
# Bug #353
|
||||
source, offset = source_and_offset(
|
||||
"import foo\n"
|
||||
"foo._|_"
|
||||
)
|
||||
filename = self.project_file("project.py", source)
|
||||
shutil.rmtree(self.project_root)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
# For some reason, this breaks a lot of other tests. Couldn't
|
||||
# figure out why.
|
||||
#
|
||||
# def test_should_not_fail_for_sys_path(self):
|
||||
# # Bug #365 / jedi#486
|
||||
# source, offset = source_and_offset(
|
||||
# "import sys\n"
|
||||
# "\n"
|
||||
# "sys.path.index(_|_\n"
|
||||
# )
|
||||
# filename = self.project_file("project.py", source)
|
||||
#
|
||||
# self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_key_error(self):
|
||||
# Bug #561, #564, #570, #588, #593, #599 / jedi#572, jedi#579,
|
||||
# jedi#590
|
||||
source, offset = source_and_offset(
|
||||
"map(lambda_|_"
|
||||
)
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_for_badly_defined_global_variable(self):
|
||||
# Bug #519 / jedi#610
|
||||
source, offset = source_and_offset(
|
||||
"""\
|
||||
def funct1():
|
||||
global global_dict_var
|
||||
global_dict_var = dict()
|
||||
|
||||
def funct2():
|
||||
global global_dict_var
|
||||
q = global_dict_var.copy_|_()
|
||||
print(q)""")
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
def test_should_not_fail_with_mergednamesdict(self):
|
||||
# Bug #563 / jedi#589
|
||||
source, offset = source_and_offset(
|
||||
u'from email import message_|_'
|
||||
)
|
||||
filename = self.project_file("project.py", source)
|
||||
|
||||
self.rpc(filename, source, offset)
|
||||
|
||||
|
||||
class RPCGetCompletionsTests(GenericRPCTests):
|
||||
METHOD = "rpc_get_completions"
|
||||
|
||||
def test_should_complete_builtin(self):
|
||||
source, offset = source_and_offset("o_|_")
|
||||
|
||||
expected = self.BUILTINS
|
||||
actual = [cand['name'] for cand in
|
||||
self.backend.rpc_get_completions("test.py",
|
||||
source, offset)]
|
||||
|
||||
for candidate in expected:
|
||||
self.assertIn(candidate, actual)
|
||||
|
||||
if sys.version_info >= (3, 5):
|
||||
JSON_COMPLETIONS = ["SONDecoder", "SONEncoder", "SONDecodeError"]
|
||||
else:
|
||||
JSON_COMPLETIONS = ["SONDecoder", "SONEncoder"]
|
||||
|
||||
def test_should_complete_imports(self):
|
||||
source, offset = source_and_offset("import json\n"
|
||||
"json.J_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
self.assertEqual(
|
||||
sorted([cand['suffix'] for cand in completions]),
|
||||
sorted(self.JSON_COMPLETIONS))
|
||||
|
||||
def test_should_complete_top_level_modules_for_import(self):
|
||||
source, offset = source_and_offset("import multi_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
if compat.PYTHON3:
|
||||
expected = ["processing"]
|
||||
else:
|
||||
expected = ["file", "processing"]
|
||||
self.assertEqual(sorted([cand['suffix'] for cand in completions]),
|
||||
sorted(expected))
|
||||
|
||||
def test_should_complete_packages_for_import(self):
|
||||
source, offset = source_and_offset("import email.mi_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
self.assertEqual([cand['suffix'] for cand in completions],
|
||||
["me"])
|
||||
|
||||
def test_should_not_complete_for_import(self):
|
||||
source, offset = source_and_offset("import foo.Conf_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
self.assertEqual([cand['suffix'] for cand in completions],
|
||||
[])
|
||||
|
||||
@unittest.skipIf((3, 3) <= sys.version_info < (3, 4),
|
||||
"Bug in jedi for Python 3.3")
|
||||
def test_should_not_fail_for_short_module(self):
|
||||
source, offset = source_and_offset("from .. import foo_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
self.assertIsNotNone(completions)
|
||||
|
||||
def test_should_complete_sys(self):
|
||||
source, offset = source_and_offset("import sys\nsys._|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
self.assertIn('path', [cand['suffix'] for cand in completions])
|
||||
|
||||
def test_should_find_with_trailing_text(self):
|
||||
source, offset = source_and_offset(
|
||||
"import threading\nthreading.T_|_mumble mumble")
|
||||
|
||||
expected = ["Thread", "ThreadError", "Timer"]
|
||||
actual = [cand['name'] for cand in
|
||||
self.backend.rpc_get_completions("test.py", source, offset)]
|
||||
|
||||
for candidate in expected:
|
||||
self.assertIn(candidate, actual)
|
||||
|
||||
def test_should_find_completion_different_package(self):
|
||||
# See issue #74
|
||||
self.project_file("project/__init__.py", "")
|
||||
source1 = ("class Add:\n"
|
||||
" def add(self, a, b):\n"
|
||||
" return a + b\n")
|
||||
self.project_file("project/add.py", source1)
|
||||
source2, offset = source_and_offset(
|
||||
"from project.add import Add\n"
|
||||
"class Calculator:\n"
|
||||
" def add(self, a, b):\n"
|
||||
" c = Add()\n"
|
||||
" c.ad_|_\n")
|
||||
file2 = self.project_file("project/calculator.py", source2)
|
||||
proposals = self.backend.rpc_get_completions(file2,
|
||||
source2,
|
||||
offset)
|
||||
self.assertEqual(["add"],
|
||||
[proposal["name"] for proposal in proposals])
|
||||
|
||||
|
||||
class RPCGetCompletionDocstringTests(object):
|
||||
def test_should_return_docstring(self):
|
||||
source, offset = source_and_offset("import json\n"
|
||||
"json.JSONEnc_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
completions.sort(key=lambda p: p["name"])
|
||||
prop = completions[0]
|
||||
self.assertEqual(prop["name"], "JSONEncoder")
|
||||
|
||||
docs = self.backend.rpc_get_completion_docstring("JSONEncoder")
|
||||
|
||||
self.assertIn("Extensible JSON", docs)
|
||||
|
||||
def test_should_return_none_if_unknown(self):
|
||||
docs = self.backend.rpc_get_completion_docstring("Foo")
|
||||
|
||||
self.assertIsNone(docs)
|
||||
|
||||
|
||||
class RPCGetCompletionLocationTests(object):
|
||||
def test_should_return_location(self):
|
||||
source, offset = source_and_offset("donaudampfschiff = 1\n"
|
||||
"donau_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
completions = self.backend.rpc_get_completions(filename,
|
||||
source,
|
||||
offset)
|
||||
prop = completions[0]
|
||||
self.assertEqual(prop["name"], "donaudampfschiff")
|
||||
|
||||
loc = self.backend.rpc_get_completion_location("donaudampfschiff")
|
||||
|
||||
self.assertEqual((filename, 1), loc)
|
||||
|
||||
def test_should_return_none_if_unknown(self):
|
||||
docs = self.backend.rpc_get_completion_location("Foo")
|
||||
|
||||
self.assertIsNone(docs)
|
||||
|
||||
|
||||
class RPCGetDefinitionTests(GenericRPCTests):
|
||||
METHOD = "rpc_get_definition"
|
||||
|
||||
def test_should_return_definition_location_same_file(self):
|
||||
source, offset = source_and_offset("import threading\n"
|
||||
"def test_function(a, b):\n"
|
||||
" return a + b\n"
|
||||
"\n"
|
||||
"test_func_|_tion(\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
location = self.backend.rpc_get_definition(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(location[0], filename)
|
||||
# On def or on the function name
|
||||
self.assertIn(location[1], (17, 21))
|
||||
|
||||
def test_should_return_location_in_same_file_if_not_saved(self):
|
||||
source, offset = source_and_offset(
|
||||
"import threading\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def other_function():\n"
|
||||
" test_f_|_unction(1, 2)\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_function(a, b):\n"
|
||||
" return a + b\n")
|
||||
filename = self.project_file("test.py", "")
|
||||
|
||||
location = self.backend.rpc_get_definition(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(location[0], filename)
|
||||
# def or function name
|
||||
self.assertIn(location[1], (67, 71))
|
||||
|
||||
def test_should_return_location_in_different_file(self):
|
||||
source1 = ("def test_function(a, b):\n"
|
||||
" return a + b\n")
|
||||
file1 = self.project_file("test1.py", source1)
|
||||
source2, offset = source_and_offset("from test1 import test_function\n"
|
||||
"test_funct_|_ion(1, 2)\n")
|
||||
file2 = self.project_file("test2.py", source2)
|
||||
|
||||
definition = self.backend.rpc_get_definition(file2,
|
||||
source2,
|
||||
offset)
|
||||
|
||||
self.assertEqual(definition[0], file1)
|
||||
# Either on the def or on the function name
|
||||
self.assertIn(definition[1], (0, 4))
|
||||
|
||||
def test_should_return_none_if_location_not_found(self):
|
||||
source, offset = source_and_offset("test_f_|_unction()\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
definition = self.backend.rpc_get_definition(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertIsNone(definition)
|
||||
|
||||
def test_should_return_none_if_outside_of_symbol(self):
|
||||
source, offset = source_and_offset("test_function(_|_)\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
definition = self.backend.rpc_get_definition(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertIsNone(definition)
|
||||
|
||||
def test_should_return_definition_location_different_package(self):
|
||||
# See issue #74
|
||||
self.project_file("project/__init__.py", "")
|
||||
source1 = ("class Add:\n"
|
||||
" def add(self, a, b):\n"
|
||||
" return a + b\n")
|
||||
file1 = self.project_file("project/add.py", source1)
|
||||
source2, offset = source_and_offset(
|
||||
"from project.add import Add\n"
|
||||
"class Calculator:\n"
|
||||
" def add(self, a, b):\n"
|
||||
" return Add_|_().add(a, b)\n")
|
||||
file2 = self.project_file("project/calculator.py", source2)
|
||||
|
||||
location = self.backend.rpc_get_definition(file2,
|
||||
source2,
|
||||
offset)
|
||||
|
||||
self.assertEqual(location[0], file1)
|
||||
# class or class name
|
||||
self.assertIn(location[1], (0, 6))
|
||||
|
||||
def test_should_find_variable_definition(self):
|
||||
source, offset = source_and_offset("SOME_VALUE = 1\n"
|
||||
"\n"
|
||||
"variable = _|_SOME_VALUE\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
self.assertEqual(self.backend.rpc_get_definition(filename,
|
||||
source,
|
||||
offset),
|
||||
(filename, 0))
|
||||
|
||||
|
||||
class RPCGetAssignmentTests(GenericRPCTests):
|
||||
METHOD = "rpc_get_assignment"
|
||||
|
||||
def test_should_return_assignment_location_same_file(self):
|
||||
source, offset = source_and_offset("import threading\n"
|
||||
"class TestClass(object):\n"
|
||||
" def __init__(self, a, b):\n"
|
||||
" self.a = a\n"
|
||||
" self.b = b\n"
|
||||
"\n"
|
||||
"testclass = TestClass(2, 4)"
|
||||
"\n"
|
||||
"testcl_|_ass(\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
location = self.backend.rpc_get_assignment(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(location[0], filename)
|
||||
# On def or on the function name
|
||||
self.assertEqual(location[1], 111)
|
||||
|
||||
def test_should_return_location_in_same_file_if_not_saved(self):
|
||||
source, offset = source_and_offset("import threading\n"
|
||||
"class TestClass(object):\n"
|
||||
" def __init__(self, a, b):\n"
|
||||
" self.a = a\n"
|
||||
" self.b = b\n"
|
||||
"\n"
|
||||
"testclass = TestClass(2, 4)"
|
||||
"\n"
|
||||
"testcl_|_ass(\n")
|
||||
filename = self.project_file("test.py", "")
|
||||
|
||||
location = self.backend.rpc_get_assignment(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(location[0], filename)
|
||||
# def or function name
|
||||
self.assertEqual(location[1], 111)
|
||||
|
||||
def test_should_return_location_in_different_file(self):
|
||||
source1 = ("class TestClass(object):\n"
|
||||
" def __init__(self, a, b):\n"
|
||||
" self.a = a\n"
|
||||
" self.b = b\n"
|
||||
"testclass = TestClass(3, 5)\n")
|
||||
file1 = self.project_file("test1.py", source1)
|
||||
source2, offset = source_and_offset("from test1 import testclass\n"
|
||||
"testcl_|_ass.a\n")
|
||||
file2 = self.project_file("test2.py", source2)
|
||||
# First jump goes to import statement
|
||||
assignment = self.backend.rpc_get_assignment(file2,
|
||||
source2,
|
||||
offset)
|
||||
# Second jump goes to test1 file
|
||||
self.assertEqual(assignment[0], file2)
|
||||
assignment = self.backend.rpc_get_assignment(file2,
|
||||
source2,
|
||||
assignment[1])
|
||||
|
||||
self.assertEqual(assignment[0], file1)
|
||||
self.assertEqual(assignment[1], 93)
|
||||
|
||||
def test_should_return_none_if_location_not_found(self):
|
||||
source, offset = source_and_offset("test_f_|_unction()\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
assignment = self.backend.rpc_get_assignment(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertIsNone(assignment)
|
||||
|
||||
def test_should_return_none_if_outside_of_symbol(self):
|
||||
source, offset = source_and_offset("testcl(_|_)ass\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
assignment = self.backend.rpc_get_assignment(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertIsNone(assignment)
|
||||
|
||||
def test_should_find_variable_assignment(self):
|
||||
source, offset = source_and_offset("SOME_VALUE = 1\n"
|
||||
"\n"
|
||||
"variable = _|_SOME_VALUE\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
self.assertEqual(self.backend.rpc_get_assignment(filename,
|
||||
source,
|
||||
offset),
|
||||
(filename, 0))
|
||||
|
||||
|
||||
class RPCGetCalltipTests(GenericRPCTests):
|
||||
METHOD = "rpc_get_calltip"
|
||||
|
||||
@unittest.skipIf(sys.version_info >= (3, 0),
|
||||
"Bug in Jedi 0.9.0")
|
||||
def test_should_get_calltip(self):
|
||||
source, offset = source_and_offset(
|
||||
"import threading\nthreading.Thread(_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
calltip = self.backend.rpc_get_calltip(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
expected = self.THREAD_CALLTIP
|
||||
|
||||
self.assertEqual(calltip, expected)
|
||||
|
||||
@unittest.skipIf(sys.version_info >= (3, 0),
|
||||
"Bug in Jedi 0.9.0")
|
||||
def test_should_get_calltip_even_after_parens(self):
|
||||
source, offset = source_and_offset(
|
||||
"import threading\nthreading.Thread(foo()_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
actual = self.backend.rpc_get_calltip(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(self.THREAD_CALLTIP, actual)
|
||||
|
||||
@unittest.skipIf(sys.version_info >= (3, 0),
|
||||
"Bug in Jedi 0.9.0")
|
||||
def test_should_get_calltip_at_closing_paren(self):
|
||||
source, offset = source_and_offset(
|
||||
"import threading\nthreading.Thread(_|_)")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
actual = self.backend.rpc_get_calltip(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(self.THREAD_CALLTIP, actual)
|
||||
|
||||
def test_should_not_missing_attribute_get_definition(self):
|
||||
# Bug #627 / jedi#573
|
||||
source, offset = source_and_offset(
|
||||
"import threading\nthreading.Thread(_|_)")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
self.backend.rpc_get_calltip(filename, source, offset)
|
||||
|
||||
def test_should_return_none_for_bad_identifier(self):
|
||||
source, offset = source_and_offset(
|
||||
"froblgoo(_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
calltip = self.backend.rpc_get_calltip(filename,
|
||||
source,
|
||||
offset)
|
||||
self.assertIsNone(calltip)
|
||||
|
||||
def test_should_remove_self_argument(self):
|
||||
source, offset = source_and_offset(
|
||||
"d = dict()\n"
|
||||
"d.keys(_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
actual = self.backend.rpc_get_calltip(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(self.KEYS_CALLTIP, actual)
|
||||
|
||||
def test_should_remove_package_prefix(self):
|
||||
source, offset = source_and_offset(
|
||||
"import decimal\n"
|
||||
"d = decimal.Decimal('1.5')\n"
|
||||
"d.radix(_|_")
|
||||
filename = self.project_file("test.py", source)
|
||||
|
||||
actual = self.backend.rpc_get_calltip(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(self.RADIX_CALLTIP, actual)
|
||||
|
||||
def test_should_return_none_outside_of_all(self):
|
||||
filename = self.project_file("test.py", "")
|
||||
source, offset = source_and_offset("import thr_|_eading\n")
|
||||
calltip = self.backend.rpc_get_calltip(filename,
|
||||
source, offset)
|
||||
self.assertIsNone(calltip)
|
||||
|
||||
def test_should_find_calltip_different_package(self):
|
||||
# See issue #74
|
||||
self.project_file("project/__init__.py", "")
|
||||
source1 = ("class Add:\n"
|
||||
" def add(self, a, b):\n"
|
||||
" return a + b\n")
|
||||
self.project_file("project/add.py", source1)
|
||||
source2, offset = source_and_offset(
|
||||
"from project.add import Add\n"
|
||||
"class Calculator:\n"
|
||||
" def add(self, a, b):\n"
|
||||
" c = Add()\n"
|
||||
" c.add(_|_\n")
|
||||
file2 = self.project_file("project/calculator.py", source2)
|
||||
|
||||
actual = self.backend.rpc_get_calltip(file2,
|
||||
source2,
|
||||
offset)
|
||||
|
||||
self.assertEqual(self.ADD_CALLTIP, actual)
|
||||
|
||||
|
||||
class RPCGetDocstringTests(GenericRPCTests):
|
||||
METHOD = "rpc_get_docstring"
|
||||
|
||||
def check_docstring(self, docstring):
|
||||
|
||||
def first_line(s):
|
||||
return s[:s.index("\n")]
|
||||
|
||||
self.assertEqual(first_line(docstring),
|
||||
self.JSON_LOADS_DOCSTRING)
|
||||
|
||||
def test_should_get_docstring(self):
|
||||
source, offset = source_and_offset(
|
||||
"import json\njson.loads_|_(")
|
||||
filename = self.project_file("test.py", source)
|
||||
docstring = self.backend.rpc_get_docstring(filename,
|
||||
source,
|
||||
offset)
|
||||
self.check_docstring(docstring)
|
||||
|
||||
def test_should_return_none_for_bad_identifier(self):
|
||||
source, offset = source_and_offset(
|
||||
"froblgoo_|_(\n")
|
||||
filename = self.project_file("test.py", source)
|
||||
docstring = self.backend.rpc_get_docstring(filename,
|
||||
source,
|
||||
offset)
|
||||
self.assertIsNone(docstring)
|
||||
|
||||
|
||||
class RPCGetNamesTests(GenericRPCTests):
|
||||
METHOD = "rpc_get_names"
|
||||
|
||||
def test_shouldreturn_names_in_same_file(self):
|
||||
filename = self.project_file("test.py", "")
|
||||
source, offset = source_and_offset(
|
||||
"def foo(x, y):\n"
|
||||
" return x + y\n"
|
||||
"c = _|_foo(5, 2)\n")
|
||||
|
||||
names = self.backend.rpc_get_names(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(names,
|
||||
[{'name': 'foo',
|
||||
'filename': filename,
|
||||
'offset': 4},
|
||||
{'name': 'x',
|
||||
'filename': filename,
|
||||
'offset': 8},
|
||||
{'name': 'y',
|
||||
'filename': filename,
|
||||
'offset': 11},
|
||||
{'name': 'x',
|
||||
'filename': filename,
|
||||
'offset': 26},
|
||||
{'name': 'y',
|
||||
'filename': filename,
|
||||
'offset': 30},
|
||||
{'name': 'c',
|
||||
'filename': filename,
|
||||
'offset': 32},
|
||||
{'name': 'foo',
|
||||
'filename': filename,
|
||||
'offset': 36}])
|
||||
|
||||
def test_should_not_fail_without_symbol(self):
|
||||
filename = self.project_file("test.py", "")
|
||||
|
||||
names = self.backend.rpc_get_names(filename,
|
||||
"",
|
||||
0)
|
||||
|
||||
self.assertEqual(names, [])
|
||||
|
||||
|
||||
class RPCGetUsagesTests(GenericRPCTests):
|
||||
METHOD = "rpc_get_usages"
|
||||
|
||||
def test_should_return_uses_in_same_file(self):
|
||||
filename = self.project_file("test.py", "")
|
||||
source, offset = source_and_offset(
|
||||
"def foo(x):\n"
|
||||
" return _|_x + x\n")
|
||||
|
||||
usages = self.backend.rpc_get_usages(filename,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(usages,
|
||||
[{'name': 'x',
|
||||
'offset': 8,
|
||||
'filename': filename},
|
||||
{'name': 'x',
|
||||
'filename': filename,
|
||||
'offset': 23},
|
||||
{'name': u'x',
|
||||
'filename': filename,
|
||||
'offset': 27}])
|
||||
|
||||
def test_should_return_uses_in_other_file(self):
|
||||
file1 = self.project_file("file1.py", "")
|
||||
file2 = self.project_file("file2.py", "\n\n\n\n\nx = 5")
|
||||
source, offset = source_and_offset(
|
||||
"import file2\n"
|
||||
"file2._|_x\n")
|
||||
|
||||
usages = self.backend.rpc_get_usages(file1,
|
||||
source,
|
||||
offset)
|
||||
|
||||
self.assertEqual(usages,
|
||||
[{'name': 'x',
|
||||
'filename': file1,
|
||||
'offset': 19},
|
||||
{'name': 'x',
|
||||
'filename': file2,
|
||||
'offset': 5}])
|
||||
|
||||
def test_should_not_fail_without_symbol(self):
|
||||
filename = self.project_file("file.py", "")
|
||||
|
||||
usages = self.backend.rpc_get_usages(filename,
|
||||
"",
|
||||
0)
|
||||
|
||||
self.assertEqual(usages, [])
|
||||
|
||||
|
||||
def source_and_offset(source):
|
||||
"""Return a source and offset from a source description.
|
||||
|
||||
>>> source_and_offset("hello, _|_world")
|
||||
("hello, world", 7)
|
||||
>>> source_and_offset("_|_hello, world")
|
||||
("hello, world", 0)
|
||||
>>> source_and_offset("hello, world_|_")
|
||||
("hello, world", 12)
|
||||
"""
|
||||
offset = source.index("_|_")
|
||||
return source[:offset] + source[offset + 3:], offset
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue