1

I am planning to write a completion extension for Emacs. Is there any way to maintain a list of source words?

I found that a lot of completion helpers use regex to scan the buffer for the candidates. I was thinking about using inverted index to maintain the list, but Emacs has no concept of a line.

These come from my inverted list idea, line concept is that supposed Emacs buffer consists of a lot pieces of smaller buffer, each piece is a line, assumed that we organize the buffer using linked list, when we editing a line, we editing a node in linked list, as line content changing, I can update my completion table, so the updating cost is minimum, I don't need to rescan the whole buffer.

For more specific, my question is how a maintain a completion table with lowest cost during editing a buffer.

So I'm stuck. Any suggestions?

5
  • 1
    What do you mean when you say "Emacs has no concept of a line"?
    – Dan
    Commented Apr 8, 2017 at 11:42
  • Yes, you can build a list of completion targets. You'll find this explained in the Emacs elisp manual. Check that out if you haven't. If you have specific questions after that, we can help.
    – Tyler
    Commented Apr 8, 2017 at 12:46
  • gnu.org/software/emacs/manual/html_node/elisp/…
    – Tyler
    Commented Apr 8, 2017 at 12:49
  • I updated my question,@Dan
    – SuJiKiNen
    Commented Apr 8, 2017 at 16:25
  • If you want to avoid rescanning the entire buffer when it changes, perhaps (elisp) Change Hooks are what you need.
    – npostavs
    Commented Apr 9, 2017 at 0:10

2 Answers 2

1

You ask, "Is there any way to maintain a list of source words?" But you do not specify what you mean by "maintain".

Here is one possibility that comes to mind, wrt maintaining a list of completion source words: Take a look at the very old but still useful and interesting (IMO) library completion.el, which has long been (and still is) part of Emacs.

The only documentation for it is its Commentary.

The idea is that (if completion-mode is on) a "database" (file) of source words is automatically filled out and updated as you type or as you move the cursor over text.

In addition, completion.el optionally provides dabbrev-style completion. From comments in completion.el:

  This method is used if there are no useful stored completions.  It is
based on dabbrev-expand with these differences :
  1) Faster (we don't use regexps)
  2) case coercion handled correctly
This is called cdabbrev to differentiate it.
  We simply search backwards through the file looking for words which
start with the same letters we are trying to complete.

By default, the updated set of source words is saved to disk when you end an Emacs session, and by default it is loaded into a subsequent session.

So this is one kind of source-words "maintaining": automatic updating as you "use" words interactively. In addition, you can easily update the source words using Lisp -- see functions add-completions-from-buffer, add-completions-from-lisp-file, and add-completions-from-tags-table. And there are commands to add or remove source words interactively.

Because few people know about this feature and it is not documented (you really have to know it is there and then open completion.el, to learn about it), I repeat the Commentary from the file here.


What to put in .emacs
-----------------------
(dynamic-completion-mode)


Documentation [Slightly out of date]
---------------------------------------------------------------------------
 (also check the documentation string of the functions)

Introduction
---------------

    After you type a few characters, pressing the "complete" key inserts
the rest of the word you are likely to type.

This watches all the words that you type and remembers them.  When
typing a new word, pressing "complete" (meta-return) "completes" the
word by inserting the most recently used word that begins with the
same characters.  If you press meta-return repeatedly, it cycles
through all the words it knows about.

 If you like the completion then just continue typing, it is as if you
entered the text by hand.  If you want the inserted extra characters
to go away, type control-w or delete.  More options are described below.

 The guesses are made in the order of the most recently "used".  Typing
in a word and then typing a separator character (such as a space) "uses"
the word.  So does moving a cursor over the word.  If no words are found,
it uses an extended version of the dabbrev style completion.

  You automatically save the completions you use to a file between
sessions.

  Completion enables programmers to enter longer, more descriptive
variable names while typing fewer keystrokes than they normally would.


Full documentation
---------------------

  A "word" is any string containing characters with either word or symbol
syntax.  [E.G. Any alphanumeric string with hyphens, underscores, etc.]
Unless you change the constants, you must type at least three characters
for the word to be recognized.  Only words longer than 6 characters are
saved.

  When you load this file, completion will be on.  I suggest you use the
compiled version (because it is noticeably faster).

 M-x completion-mode toggles whether or not new words are added to the
database by changing the value of enable-completion.

 SAVING/LOADING COMPLETIONS
  Completions are automatically saved from one session to another
(unless save-completions-flag or enable-completion is nil).
Activating this minor-mode (calling completion-initialize) loads
a completions database for a saved completions file
(default: ~/.completions).  When you exit, Emacs saves a copy of the
completions that you often use.  When you next start, Emacs loads in
the saved completion file.

  The number of completions saved depends loosely on
*saved-completions-decay-factor*.  Completions that have never been
inserted via "complete" are not saved.  You are encouraged to experiment
with different functions (see compute-completion-min-num-uses).

  Some completions are permanent and are always saved out.  These
completions have their num-uses slot set to T.  Use
add-permanent-completion to do this

  Completions are saved only if enable-completion is T.  The number of old
versions kept of the saved completions file is controlled by
completions-file-versions-kept.

COMPLETE KEY OPTIONS
  The complete function takes a numeric arguments.
 control-u :: leave the point at the beginning of the completion rather
              than the middle.
 a number  :: rotate through the possible completions by that amount
 `-'       :: same as -1 (insert previous completion)

HOW THE DATABASE IS MAINTAINED
 <write>

UPDATING THE DATABASE MANUALLY
  m-x kill-completion
    kills the completion at point.
  m-x add-completion
  m-x add-permanent-completion

UPDATING THE DATABASE FROM A SOURCE CODE FILE
  m-x add-completions-from-buffer
    Parses all the definition names from a C or LISP mode buffer and
    adds them to the completion database.

  m-x add-completions-from-lisp-file
    Parses all the definition names from a C or Lisp mode file and
    adds them to the completion database.

UPDATING THE DATABASE FROM A TAGS TABLE
  m-x add-completions-from-tags-table
    Adds completions from the current tags-table-buffer.

HOW A COMPLETION IS FOUND
 <write>

STRING CASING
  Completion is string case independent if case-fold-search has its
 normal default of T.  Also when the completion is inserted the case of the
 entry is coerced appropriately.
 [E.G.  APP --> APPROPRIATELY     app --> appropriately
        App --> Appropriately]

INITIALIZATION
 The form `(completion-initialize)' initializes the completion system by
trying to load in the user's completions.  After the first call, further
calls have no effect so one should be careful not to put the form in a
site's standard site-init file.

And here is some more doc in the form of comments from completion.el:

---------------------------------------------------------------------------
"Symbol" parsing functions
---------------------------------------------------------------------------
The functions symbol-before-point, symbol-under-point, etc. quickly return
an appropriate symbol string.  The strategy is to temporarily change
the syntax table to enable fast symbol searching.  There are three classes
of syntax in these "symbol" syntax tables ::

syntax (?_) - "symbol" chars (e.g. alphanumerics)
syntax (?w) - symbol chars to ignore at end of words (e.g. period).
syntax (? ) - everything else

Thus by judicious use of scan-sexps and forward-word, we can get
the word we want relatively fast and without consing.

Why do we need a separate category for "symbol chars to ignore at ends" ?
For example, in LISP we want starting :'s trimmed
so keyword argument specifiers also define the keyword completion.  And,
for example, in C we want `.' appearing in a structure ref. to
be kept intact in order to store the whole structure ref.; however, if
it appears at the end of a symbol it should be discarded because it is
probably used as a period.

Here is the default completion syntax ::
Symbol chars :: A-Z a-z 0-9 @ / \ * + ~ $ < > %
Symbol chars to ignore at ends :: _ : . -
Separator chars. :: <tab> <space> ! ^ & ( ) = ` | { } [ ] ; " ' #
                    , ? <Everything else>

Mode specific differences and notes ::
 LISP diffs ->
   Symbol chars :: ! & ? = ^

C diffs ->
  Separator chars :: + * / : %
 A note on the hyphen (`-').  Perhaps the hyphen should also be a separator
char., however, we wanted to have completion symbols include pointer
references.  For example, "foo->bar" is a symbol as far as completion is
concerned.

FORTRAN diffs ->
  Separator chars :: + - * / :

Pathname diffs ->
  Symbol chars :: .
 Of course there is no pathname "mode" and in fact we have not implemented
this table.  However, if there was such a mode, this is what it would look
like.
2
  • I checked that before,when buffer changed,it will reseach the buffer.
    – SuJiKiNen
    Commented Apr 8, 2017 at 16:28
  • I don't see why you couldn't combine the use of an inverted index with this, in particular with the automatic detection of words as a user interacts with text (including using completion).
    – Drew
    Commented Apr 8, 2017 at 16:33
0

As mentioned by npostavs, you can ask Emacs to tell you about all buffer modifications via (elisp) Change Hooks.

These modifications are described at the level of characters rather than lines, but it is easy to "round it up" to whole lines. This is for example what font-lock does.

This said, depending on the details of your "inverted list", you may not need to round up to whole lines and can instead update your data-structure only for those characters that were modified.

FWIW, I think it'd be great to have a package which builds and maintains a suffix-tree this way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.