zk-phi / git-complete

Yet another completion engine powered by "git grep"
67 stars 5 forks source link
emacs

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:

=git-complete= CAN'T:

EXTRA FEATURES:

*** See also:

The =git grep= idea is taken from =auto-programming.el= by hitode909.

https://github.com/hitode909/emacs-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)

** Customizations

See "How it works" section for the options below:

** How it works

There are three methods to collect completions:

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

  1. 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(); : import React from 'react'; : export default class extends React.Component { : import ReactDOM from 'react-dom'; : ReactDOM.render(); : ...

  2. 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

  1. 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(); : import React from 'react'; : export default class extends React.Component { : import ReactDOM from 'react-dom'; : ReactDOM.render(); : ...

  2. 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(); : from 'react'; : .Component { : DOM from 'react-dom'; : DOM.render(); : ...

  3. 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()= is not, since it does not appear "frequently".

  4. 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; : |

  1. 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; : -- : ...

  2. 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 | : | ... | ... | ... |

  3. 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

  1. Delete all characters in the current line

    : |

  2. Insert the completion

    : export default class extends React.Component { : |

  3. 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

  1. Insert the completion after the cursor

    : var foo = moment().format("YYYY-MM-DD HH:mm:ss",|

  2. 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",|)