Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
8.1 KiB

преди 4 години
  1. ;;; company-tng.el --- company-mode configuration for single-button interaction
  2. ;; Copyright (C) 2017 Free Software Foundation, Inc.
  3. ;; Author: Nikita Leshenko
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;; company-tng (Tab and Go) allows you to perform completion using just TAB.
  18. ;; Pressing it will both select the next completion candidate in the list and
  19. ;; insert it into the buffer (or make it look like it's inserted, in fact).
  20. ;;
  21. ;; It cycles the candidates like `yank-pop' or `dabbrev-expand' or Vim:
  22. ;; Pressing TAB selects the first item in the completion menu and inserts it in
  23. ;; the buffer. Pressing TAB again selects the second item and replaces the
  24. ;; "inserted" item with the second one. This can continue as long as the user
  25. ;; wishes to cycle through the menu. You can also press S-TAB to select the
  26. ;; previous candidate, of course.
  27. ;;
  28. ;; The benefits are that you only have to use one shortcut key and there is no
  29. ;; need to confirm the entry.
  30. ;;
  31. ;; Usage:
  32. ;;
  33. ;; To apply the default configuration for company-tng call
  34. ;; `company-tng-configure-default' from your init script.
  35. ;;
  36. ;; You can also configure company-tng manually:
  37. ;;
  38. ;; Add `company-tng-frontend' to `company-frontends':
  39. ;;
  40. ;; (add-to-list 'company-frontends 'company-tng-frontend)
  41. ;;
  42. ;; We recommend to bind TAB to `company-select-next', S-TAB to
  43. ;; `company-select-previous', and unbind RET and other now-unnecessary
  44. ;; keys from `company-active-map':
  45. ;;
  46. ;; (define-key company-active-map (kbd "TAB") 'company-select-next)
  47. ;; (define-key company-active-map (kbd "<backtab>") 'company-select-previous)
  48. ;; (define-key company-active-map (kbd "RET") nil)
  49. ;;
  50. ;; Note that it's not necessary to rebind keys to use this frontend,
  51. ;; you can use the arrow keys or M-n/M-p to select and insert
  52. ;; candidates. You also need to decide which keys to unbind, depending
  53. ;; on whether you want them to do the Company action or the default
  54. ;; Emacs action (for example C-s or C-w).
  55. ;;
  56. ;; We recommend to disable `company-require-match' to allow free typing at any
  57. ;; point.
  58. ;;
  59. ;; By default, company-tng doesn't work well with backends that use
  60. ;; `post-completion' (for actions such as expanding snippets in
  61. ;; company-yasnippet or company-template). In company-tng, completion candidates
  62. ;; are inserted into the buffer as the user selects them and the completion is
  63. ;; finished implicitly when the user continues typing after selecting a
  64. ;; candidate. Modifying the buffer (by expanding a snippet) when the user
  65. ;; continues typing would be surprising and undesirable, since the candidate was
  66. ;; already inserted into the buffer. For this reason company-tng disables
  67. ;; `post-completion' in all backends.
  68. ;;
  69. ;; YASnippet and company-tng both use TAB, which causes conflicts. The
  70. ;; recommended way to use YASnippet with company-tng is to choose a different
  71. ;; key for expanding a snippet and moving to the next snippet field:
  72. ;;
  73. ;; (define-key yas-minor-mode-map "\C-j" 'yas-expand)
  74. ;; (define-key yas-keymap "\C-j" 'yas-next-field-or-maybe-expand)
  75. ;; (dolist (keymap (list yas-minor-mode-map yas-keymap))
  76. ;; (define-key keymap (kbd "TAB") nil)
  77. ;; (define-key keymap [(tab)] nil))
  78. ;;; Code:
  79. (require 'company)
  80. (require 'cl-lib)
  81. (defvar-local company-tng--overlay nil)
  82. ;;;###autoload
  83. (defun company-tng-frontend (command)
  84. "When the user changes the selection at least once, this
  85. frontend will display the candidate in the buffer as if it's
  86. already there and any key outside of `company-active-map' will
  87. confirm the selection and finish the completion."
  88. (cl-case command
  89. (show
  90. (let ((ov (make-overlay (point) (point))))
  91. (setq company-tng--overlay ov)
  92. (overlay-put ov 'priority 2))
  93. (advice-add 'company-select-next :before-until 'company-tng--allow-unselected)
  94. (advice-add 'company-fill-propertize :filter-args 'company-tng--adjust-tooltip-highlight))
  95. (update
  96. (let ((ov company-tng--overlay)
  97. (selected (nth company-selection company-candidates))
  98. (prefix (length company-prefix)))
  99. (move-overlay ov (- (point) prefix) (point))
  100. (overlay-put ov
  101. (if (= prefix 0) 'after-string 'display)
  102. (and company-selection-changed selected))))
  103. (hide
  104. (when company-tng--overlay
  105. (delete-overlay company-tng--overlay)
  106. (kill-local-variable 'company-tng--overlay))
  107. (advice-remove 'company-select-next 'company-tng--allow-unselected)
  108. (advice-remove 'company-fill-propertize 'company-tng--adjust-tooltip-highlight))
  109. (pre-command
  110. (when (and company-selection-changed
  111. (not (company--company-command-p (this-command-keys))))
  112. (company--unread-this-command-keys)
  113. (setq this-command 'company-complete-selection)
  114. (advice-add 'company-call-backend :before-until 'company-tng--supress-post-completion)))))
  115. ;;;###autoload
  116. (defun company-tng-configure-default ()
  117. "Applies the default configuration to enable company-tng."
  118. (setq company-require-match nil)
  119. (setq company-frontends '(company-tng-frontend
  120. company-pseudo-tooltip-frontend
  121. company-echo-metadata-frontend))
  122. (let ((keymap company-active-map))
  123. (define-key keymap [return] nil)
  124. (define-key keymap (kbd "RET") nil)
  125. (define-key keymap [tab] 'company-select-next)
  126. (define-key keymap (kbd "TAB") 'company-select-next)
  127. (define-key keymap [backtab] 'company-select-previous)
  128. (define-key keymap (kbd "S-TAB") 'company-select-previous)))
  129. (defun company-tng--allow-unselected (&optional arg)
  130. "Advice `company-select-next' to allow for an 'unselected'
  131. state. Unselected means that no user interaction took place on the
  132. completion candidates and it's marked by setting
  133. `company-selection-changed' to nil. This advice will call the underlying
  134. `company-select-next' unless we need to transition to or from an unselected
  135. state.
  136. Possible state transitions:
  137. - (arg > 0) unselected -> first candidate selected
  138. - (arg < 0) first candidate selected -> unselected
  139. - (arg < 0 wrap-round) unselected -> last candidate selected
  140. - (arg < 0 no wrap-round) unselected -> unselected
  141. There is no need to advice `company-select-previous' because it calls
  142. `company-select-next' internally."
  143. (cond
  144. ;; Selecting next
  145. ((or (not arg) (> arg 0))
  146. (unless company-selection-changed
  147. (company-set-selection (1- (or arg 1)) 'force-update)
  148. t))
  149. ;; Selecting previous
  150. ((< arg 0)
  151. (when (and company-selection-changed
  152. (< (+ company-selection arg) 0))
  153. (company-set-selection 0)
  154. (setq company-selection-changed nil)
  155. (company-call-frontends 'update)
  156. t)
  157. )))
  158. (defun company-tng--adjust-tooltip-highlight (args)
  159. "Prevent the tooltip from highlighting the current selection if it wasn't
  160. made explicitly (i.e. `company-selection-changed' is true)"
  161. (unless company-selection-changed
  162. ;; The 4th arg of `company-fill-propertize' is selected
  163. (setf (nth 3 args) nil))
  164. args)
  165. (defun company-tng--supress-post-completion (command &rest args)
  166. "Installed as a :before-until advice on `company-call-backend' and
  167. prevents the 'post-completion command from being delivered to the backend
  168. for the next iteration. post-completion do things like expand snippets
  169. which are undesirable because completions are implicit in company-tng and
  170. visible side-effects after the completion are surprising."
  171. (when (eq command 'post-completion)
  172. (advice-remove 'company-call-backend 'company-tng--supress-post-completion)
  173. t))
  174. (provide 'company-tng)
  175. ;;; company-tng.el ends here