git-complete
git-complete copied to clipboard
Yet another completion engine powered by "git grep"
- git-complete.el
Yet another completion engine powered by =git grep=
=git grep= を使った補完エンジン
** Description
=git-complete= provides an interactive command which, when invoked, scans the current git project with =git grep= and suggests what you may want to insert.
[[screencast.gif]]
=git-complete= CAN:
-
complete not just a symbol but the whole idiom if appropreate, unlike other completion engines (rather like snippet engines)
-
be used as an "omni (smart) completion" engine, i.e. =git-complete= tries to suggest expressions you may want to insert next, according to the context, even when you don't remember it, by grepping your project (class methods after a class name, typical argument for a function, for examples)
-
be used with no per-language configurations or dictionaries, unlike snippet engines or omni-completion engines
=git-complete= CAN'T:
-
complete expressions which has not been used in the git project yet
-
start completion automatically, since it's a bit time-consuming to grep over the project (especially for the first invokation)
-
be 100% accurate, since =git-complete= has no knowledge about the language you are coding in
EXTRA FEATURES:
-
"autopair"
- =git-complete= (optionally) tries to keep the parentheses balanced by inserting or merging some parens if appropreate
-
DWIM newline insertion
- =git-complete= tries to insert newline after completion if you may want so
*** See also:
The =git grep= idea is taken from =auto-programming.el= by hitode909.
https://github.com/hitode909/emacs-auto-programming
-
Atom version: =atom-auto-programming= by the author of =auto-programming.el=
- https://github.com/hitode909/atom-auto-programming
-
Vim version: =vim-auto-programming= by haya14busa
- https://github.com/haya14busa/vim-auto-programming
** Quickstart *** Installation
#+begin_src emacs-lisp (require 'git-complete) #+end_src
and (optionally) bind some keys.
#+begin_src emacs-lisp (global-set-key (kbd "C-c C-c") 'git-complete) #+end_src
You may also invoke git-complete with =M-x git-complete=.
Note that you also need to install =git= if it's not installed yet.
*** Examples
(Consider "|" as the cursor in following examples)
-
after a part of a package name:
#+begin_src perl SHA| #+end_src
git-complete completes the import statement.
#+begin_src perl use Digest::SHA; | #+end_src
-
after a constructor:
#+begin_src javascript var foo = moment().| #+end_src
git-complete suggests method names frequently used in your project.
#+begin_src javascript var foo = moment().format(| #+end_src
and =M-x git-complete= (again) suggests typical arguments to the method frequently used in your project.
#+begin_src javascript var foo = moment().format("YYYY-MM-DD HH:mm:ss"| #+end_src
-
after a newline:
#+begin_src perl use strict; | #+end_src
suggests next line which usually follows the line =use strict;= in your project.
#+begin_src perl use strict; use warnings; | #+end_src
** Customizations
-
=git-complete-enable-autopair= : either git-complete should keep the parenthesis balance during completion
-
=git-complete-ignore-case= : either to use =--ignore-case= option or not when git grepping
-
=git-complete-grep-function= : function used to grep over the repo. git-complete by default uses =git grep= but you may tell git-complete to use =rg= instead by setting this variable to ='git-complete-ripgrep=
See "How it works" section for the options below:
- =git-complete-threshold=
- =git-complete-whole-line-completion-threshold=
- =git-complete-next-line-completion-threshold=
- =git-complete-repeat-completion=
** How it works
There are three methods to collect completions:
- whole current-line completion
- omni current-line completion
- omni next-line completion
User is prompted to select one of the completions, and the selected completion is inserted to the buffer in different ways according to its type.
*** Completion collection **** Whole current-line completion
example:
: React| * consider | as the cursor
-
Collect lines with "React" in your git repo, by =git grep=-ing with "React"
: $ git grep -F -h "React" : import React from 'react'; : export default class extends React.Component { : export default class extends React.Component { : import React from 'react'; : export default class extends React.Component { : import React from 'react'; : import ReactDOM from 'react-dom'; : export default class extends React.Component { : ReactDOM.render(<MyComponent />); : import React from 'react'; : export default class extends React.Component { : import ReactDOM from 'react-dom'; : ReactDOM.render(<AnotherComponent />); : ...
-
If some identical lines appear "frequently" (as defined by =git-complete-whole-line-completion-threshold=), they are added to the completions list, as "whole-line" completions.
: | | frequency | type | : +-------------------------------------------------+-----------+------------| : | export default class extends React.Component{\n | 60% | whole-line | : | import React from 'react';\n | 30% | whole-line | : | ... | ... | ... |
**** Omni current-line completion
example:
: React| * consider | as the cursor
-
Collect lines with "React" in your git repo, by =git grep=-ing with "React"
: $ git grep -F -h "React" : import React from 'react'; : export default class extends React.Component { : export default class extends React.Component { : import React from 'react'; : export default class extends React.Component { : import React from 'react'; : import ReactDOM from 'react-dom'; : export default class extends React.Component { : ReactDOM.render(<MyComponent />); : import React from 'react'; : export default class extends React.Component { : import ReactDOM from 'react-dom'; : ReactDOM.render(<AnotherComponent />); : ...
-
Trim each lines found in 1. as follows:
-
Find the query string ("React" in this case) inside the line and remove characters before the query and the query itself.
-
If the line has more close parens than open parens, remove characters after the innermost matching close paren.
: from 'react'; : .Component { : .Component { : from 'react'; : .Component { : from 'react'; : DOM from 'react-dom'; : .Component { : DOM.render(<MyComponent />); : from 'react'; : .Component { : DOM from 'react-dom'; : DOM.render(<AnotherComponent />); : ...
-
-
If some identical idioms appear "frequently" (as defined in =git-complete-threshold=) at the beginning of the lines, add the idioms to the completions list as "omni" completions.
: | | frequency | type | : +-------------------------+-----------+------| : | .Component {\n | 60% | omni | : | from 'react';\n | 30% | omni | : | DOM from 'react-dom';\n | 5% | omni | : | DOM.render(< | 5% | omni | : | ... | ... | ... |
Note that =DOM.render(<= is added to the list but =DOM.render(<MyComponent />)= is not, since it does not appear "frequently".
-
If no completions are found, shorten the query by one subword (configurable via =git-cmopletion-omni-completion-type=) from the beginning and =git grep= again, then back to the step 3. .
example:
: var foo = bar(MyClass.|
The query =var foo = bar(MyClass.= is too specific to find some "frequent" idioms, thus shortened to =foo = bar(MyClass.=, =bar(MyClass.= then =MyClass.= which may give some "frequent" idioms: method names of the class =MyClass=.
When the query is shortened, all completions will be type of "omni", since the step 2. is skipped.
**** Omni next-line completion
example:
: use strict; : |
-
Collect lines next to =use strict;= in your git repo, by grepping with =use strict;=
: > git grep -F -h -A1 "use strict;" : use strict; : sub foo { : -- : use strict; : use warnings; : -- : use strict; : use warnings; : -- : use strict; : sub bar { : -- : use strict; : use utf8; : -- : ...
-
Find identical lines as like the step 2. of "Whole current-line completion", according to =git-complete-next-line-completion-threshold=
: | | frequency | type | : +-----------------+-----------+------| : | use warnings;\n | 80% | omni | : | use utf8;\n | 20% | omni | : | ... | ... | ... |
-
If no completions are found, shorten the query and repeat like the step 3 of "Omni current-line completion".
*** Completion insertion **** Whole-line completion
example:
: React|
when you select a "whole-line" completion like below:
: export default class extends React.Component {\n
then
-
Delete all characters in the current line
: |
-
Insert the completion
: export default class extends React.Component { : |
-
Add some close parens as needed (if "autopair" feature is not disabled)
: export default class extends React.Component { : | : }
**** Omni completion
example:
: var foo = moment().format|
when you select a "omni" completion like below:
: ("YYYY-MM-DD HH:mm:ss",
then
-
Insert the completion after the cursor
: var foo = moment().format("YYYY-MM-DD HH:mm:ss",|
-
Add some close parens as needed (if "autopair" feature is not disabled) after the cursor
: var foo = moment().format("YYYY-MM-DD HH:mm:ss",|)