# _M.textadept.adeptsense

Code autocompletion and documentation support for programming languages.

## Overview

Adeptsense is a form of autocompletion for programming. It has the means to
supply a list of potential completions for classes, member functions and
fields, packages, etc and display their documentation in the form of a
calltip. This document provides the information necessary in order to write a
new Adeptsense for a language. For illustrative purposes, an Adeptsense for
Lua will be created. More advanced techniques are covered later.

## Creating an Adeptsense

Adeptsenses exist per-language and are typically defined in a
[language-specific module][]. First check to see if the module for your
language has an Adeptsense. If not, you will need to create one. The language
modules included with Textadept have Adeptsenses so they can be used for
reference. If your language is similar to any of those languages, you can
copy and modify the existing language's Adeptsense, saving some time and
effort.

[language-specific module]: _M.html#Language-Specific.Modules

### Terminology

Not all languages have "classes", "functions", and "fields" in the full sense
of the word. Normally classes are referred to as objects in Object Oriented
Programming (OOP), functions are class or instance methods,and fields are
class or instance properties. For example a "Cat" class may have a "color"
field and a "meow" function. To Adeptsense, the term "class" is simply a
container for "function" and "field" completions. "functions" and "fields"
are only distinguished by an icon in the completion list.

For Lua, consider modules and tables as "classes", functions as "functions",
and module/table keys as "fields".

### Introduction

Open the language-specific module for editing and create a new instance of an
Adeptsense.

    $> # from either _HOME or _USERHOME:
    $> cd modules/lua/
    $> textadept init.lua

    sense = _M.textadept.adeptsense.new('lua')

Where 'lua' is replaced by your language's name.

### Syntax Options

The syntax of different languages varies so the Adeptsense must be configured
for your language in order to function properly. See the [`syntax`](#syntax)
table documentation for all options.

#### `self`

The first syntax option is `syntax.self`. While Lua has a `self` identifier,
it is not used in the usual sense for a class instance so it will just be
ignored.

#### `class_definition`

Next is `syntax.class_definition`. Lua does not really have the "class"
concept most OOP programmers are used to, but modules do behave somewhat like
classes.

    sense.syntax.class_definition = 'module%s*%(?%s*[\'"]([%w_%.]+)'

The "class"'s name is the identifier in quotes.

#### `word_chars`

Lua words already consist of the default `%w_` so no changes are necessary.

#### `symbol_chars`

In addition to the usual `[%w_%.]` symbol characters, Lua also allows symbols
to contain a ':'.

    sense.syntax.symbol_chars = '[%w_%.:]'

#### `type_declarations`

Since Lua has no type declarations (e.g. `int x` in C), the
`syntax.type_declarations` table should be empty:

    sense.syntax.type_declarations = {}

#### `type_declarations_exclude`

Since Lua has no type declarations, no changes are necessary.

#### `type_assignments`

Sometimes a type can be inferred by the right side of a variable assignment.
In the Lua code `local foo = 'bar'`, the variable `foo` has type `string`.
Similarly, in `local foo = _M.textadept.adeptsense`, `foo` has type
`_M.textadept.adeptsense`.

    sense.syntax.type_assignments = {
      ['^[\'"]'] = 'string', -- foo = 'bar' or foo = "bar"
      ['^([%w_%.]+)'] = '%1' -- foo = _M.textadept.adeptsense
    }

Note the '^' in the pattern. The beginning of the right hand side of the
assignment should be matched, otherwise `local foo = bar('baz')` could infer
an incorrect type.

### Completion Lists

The [`completions`](#completions) table contains the completion lists for
all classes. Each table entry key is the class's name and the value is a
table of `functions` and `fields` lists. The general form is:

    sense.completions = {
      ['class1'] = {
        functions = {'fun1', 'fun2', ...},
        fields = {'f1', 'f2', ...}
      },
      ['class2'] = ...,
      ...
    }

Obviously manually creating completion lists would be incredibly
time-consuming so there is a shortcut method.

#### Ctags

Adeptsense recognizes the output from [Ctags][] and can populate the
`completions` table from it with a little bit of help. Ctags has a list of
"kinds" for every language. You can see them by running `ctags --list-kinds`
in your shell. Since Adeptsense only cares about classes, functions, and
fields, you need to let it know which kind of tag is which. Unfortunately,
Lua support in Ctags is not good at all. Instead, Textadept has a utility
(*modules/lua/adeptsensedoc.lua*) to generate a fake set of tags that is more
useful. Functions are tagged `'f'` and should be recognized as such; table
keys are tagged `'t'` and should be recognized as fields; module fields,
`'F'`, should be fields; and modules, `'m'`, should be classes:

    sense.ctags_kinds = {
      f = _M.textadept.adeptsense.FUNCTION,
      F = _M.textadept.adeptsense.FIELD,
      m = _M.textadept.adeptsense.CLASS,
      t = _M.textadept.adeptsense.FIELD,
    }

To load a default set of Ctags, use [`load_ctags()`](#load_ctags).

    sense:load_ctags(_HOME..'/modules/lua/tags', true)

Textadept comes with a set of Ctags for its Lua API.

[ctags]: http://ctags.sourceforge.net

### API Documentation

Adeptsense can show API documentation for symbols from files specified in its
[`api_files`](#api_files) table. See the previous link for documentation on
how the API file should be structured.

    sense.api_files = {_HOME..'/modules/lua/api'}

### Triggers

Triggers are characters or character sequences that trigger an autocompletion
list to be displayed. Lua has two characters that can do so: '.' and ':'. The
'.' should autocomplete both fields and functions while ':' should
autocomplete only functions. This is specified using
[`add_trigger()`](#add_trigger).

    sense:add_trigger('.')
    sense:add_trigger(':', false, true)

### User-Settings

Finally, you should allow the users of your Adeptsense to supply their own
Ctags and API files in addition to any default ones you loaded or specified
earlier:

    -- Load user tags and apidoc.
    if lfs.attributes(_USERHOME..'/modules/lua/tags') then
      sense:load_ctags(_USERHOME..'/modules/lua/tags')
    end
    if lfs.attributes(_USERHOME..'/modules/lua/api') then
      sense.api_files[#sense.api_files + 1] = _USERHOME..'/modules/lua/api'
    end

### Summary

The above method of setting syntax options, Ctags kinds, and trigger
characters for an Adeptsense is sufficient for most static and some dynamic
languages. The rest of this document is devoted to more complex techniques.

### Fine-Tuning

Sometimes Adeptsense's default behavior is not sufficient. Maybe the
`type_declarations` and `type_assignments` tables used by the
[`get_class()`](#get_class) function are not granular enough. Maybe some
symbols can contain more than just the `syntax.symbol_chars` used by
[`get_symbol()`](#get_symbol). Adeptsense allows these functions to be
overridden.

    function sense:get_class(symbol)
      if condition then
        return self.super.get_class(self, symbol) -- default behavior
      else
        -- different behavior
      end
    end

The default Adeptsense functions are called by using the `self.super`
reference.

#### Examples for Ruby

In Ruby, everything is an object -- even numbers. Since numbers do not have
a type declaration, the [`get_class()`](#get_class) function should return
`Integer` or `Float` if the symbol is a number.

    function sense:get_class(symbol)
      local class = self.super.get_class(self, symbol)
      if class then return class end
      -- Integers and Floats.
      if tonumber(symbol:match('^%d+%.?%d*$')) then
        return symbol:find('%.') and 'Float' or 'Integer'
      end
      return nil
    end

Note that there is no plus or minus prefix in the pattern. This is because
'+' or '-' characters are not a part of `syntax.symbol_chars` so a symbol
will not contain either of them.

Like numbers, the syntax for constructing strings, arrays, hashes, and the
like should also be considered as symbols. `[foo].` should show a completion
list with array instance methods:

    function sense:get_symbol()
      local line, p = buffer:get_cur_line()
      if line:sub(1, p):match('%[.-%]%s*%.$') then return 'Array', '' end
      return self.super.get_symbol(self)
    end

The Ruby module Adeptsense has a more complicated version of this function
that handles strings, hashes, symbols, and regexps as well. Please refer to
it for more information.

#### Examples for Java

Autocomplete of Java `import` statements is something nice to have. Ctags
produces a tag for packages so it is rather straightforward to build an
import completion list.

Since Adeptsense ignores any tags not mapped to `classes`, `functions`, or
`fields` in [`ctags_kinds`](#ctags_kinds), it passes an unknown tag to the
[`handle_ctag()`](#handle_ctag) function. In this case, package ('p') tags
need to be handled.

    function sense:handle_ctag(tag_name, file_name, ex_cmd, ext_fields)
      if ext_fields:sub(1, 1) ~= 'p' then return end -- not a package
      if not self.imports then self.imports = {} end
      local import = self.imports
      for package in tag_name:gmatch('[^.]+') do
        if not import[package] then import[package] = {} end
        import = import[package]
      end
      import[#import + 1] = file_name:match('([^/\\]-)%.java$')
    end

Now that we have a list of import completions, it should be activated by the
normal trigger ('.'), but only on a line that contains an `import` statement.
The [`get_completions`](#get_completions) function needs to be overridden to
use the `import` table's completions when necessary.

    function sense:get_completions(symbol, ofields, ofunctions)
      if not buffer:get_cur_line():find('^%s*import') then
        return self.super.get_completions(self, symbol, ofields, ofunctions)
      end
      if symbol == 'import' then symbol = '' end -- top-level import
      local c = {}
      local import = self.imports or {}
      for package in symbol:gmatch('[^%.]+') do
        if not import[package] then return nil end
        import = import[package]
      end
      for k, v in pairs(import) do
        c[#c + 1] = type(v) == 'table' and k..'?1' or v..'?2'
      end
      table.sort(c)
      return c
    end

Note that `'?1'` and `'?2'` are appended to each completion entry. These tell
Adeptsense which icon to display in the autocompletion list. If no icon
information is given, no icon is displayed. `1` is for fields and `2` is for
functions. In this case, the icons are used only to distinguish between a
parent package and a package with no children since parents have an
additional list of completions.

Finally since an `imports` table was created, it should be cleared when the
Adeptsense is cleared to free up memory immediately. When this happens,
[`handle_clear()`](#handle_clear) is called.

    function sense:handle_clear()
      self.imports = {}
    end

### Child Language Adeptsenses

When Adeptsense completion is triggered, the Adeptsense for the language at
the *caret position* is used, not necessarily the parent language's
Adeptsense. For example, when editing CSS inside of an HTML file, the user
expects the CSS Adeptsense to be used. However, child language Adeptsenses
are not loaded automatically and must be loaded by the parent language
module. For the case of CSS in HTML, the HTML module's *init.lua* must
contain:

    -- Load CSS Adeptsense.
    if not _M.css then _M.css = require('css') end

You will have to do something similar if you are writing an Adeptsense for a
child lexer language.

### Generating Lua Adeptsense

You can generate Lua Adeptsense for your own modules using the Lua language
module's *adeptsensedoc.lua* module with [LuaDoc][]:

    luadoc -d . --doclet _HOME/modules/lua/adeptsensedoc [module(s)]

where `_HOME` is where Textadept is installed. The *tags* and *api* files are
output to the current directory and can be loaded via
[`load_ctags()`](#load_ctags) and [`api_files`](#api_files) respectively.

[LuaDoc]: http://keplerproject.github.com/luadoc/

#### Module Fields

Not only does the Lua Adeptsense generator recognize functions and tables
within modules, but it also recognizes module fields and their types with a
certain syntax:

<pre><code>---
-- Module documentation.
-- &#64;field field_name (type)
--   Field documentation.
</code></pre>

or

<pre><code>---
-- Module documentation
-- * `field_name` (type)
--   Field documentation.
--   Multiple documentation lines must be indented.
</code></pre>

Please note the latter ``-- * `field_name` `` syntax can appear anywhere
inside a module, not just the module LuaDoc.

- - -

## Fields

- - -

<a id="CLASS"></a>
### `CLASS` (string)

Ctags kind for Adeptsense classes.

- - -

<a id="FIELD"></a>
### `FIELD` (string)

Ctags kind for Adeptsense fields.

- - -

<a id="FIELDS"></a>
### `FIELDS` (string)

XPM image for Adeptsense fields.

- - -

<a id="FUNCTION"></a>
### `FUNCTION` (string)

Ctags kind for Adeptsense functions.

- - -

<a id="FUNCTIONS"></a>
### `FUNCTIONS` (string)

XPM image for Adeptsense functions.

- - -

<a id="always_show_globals"></a>
### `always_show_globals` (bool)

Include globals in the list of completions offered.
  Globals are classes, functions, and fields that do not belong to another
  class. They are contained in `sense.completions['']`.
  The default value is `true`.

- - -


## Functions

- - -

<a id="add_trigger"></a>
### `add_trigger`(*sense, c, only\_fields, only\_functions*)

Sets the trigger character(s) *c* for autocompletion.
If *only_fields* is `true`, the trigger only completes fields. If
*only_functions* is `true`, the trigger only completes functions.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.
* *`c`*: The character(s) that triggers the autocompletion. You can have up
  to two characters.
* *`only_fields`*: Optional flag indicating whether or not this trigger only
  completes fields. The default value is `false`.
* *`only_functions`*: Optional flag indicating whether or not this trigger
  only completes functions. The default value is `false`.

Usage:

* `sense:add_trigger('.')`
* `sense:add_trigger(':', false, true) -- only functions`
* `sense:add_trigger('->')`

- - -

<a id="clear"></a>
### `clear`(*sense*)

Clears the Adeptsense for loading new Ctags or project files.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.

- - -

<a id="complete"></a>
### `complete`(*sense, only\_fields, only\_functions*)

Shows an autocompletion list of functions (unless *only_fields* is `true`)
and fields (unless *only_funcs* is `true`) for the symbol behind the caret,
returning `true` on success.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`. If `nil`, uses
  the current language's Adeptsense (if it exists).
* *`only_fields`*: Optional flag indicating whether or not to return a list
  of only fields. The default value is `false`.
* *`only_functions`*: Optional flag indicating whether or not to return a
  list of only functions. The default value is `false`.

Return:

* `true` on success or `false`.

See also:

* [`get_symbol`](#get_symbol)
* [`get_completions`](#get_completions)

- - -

<a id="get_apidoc"></a>
### `get_apidoc`(*sense, symbol*)

Returns a list of apidocs for *symbol* name.
The list contains a `pos` key with the index of the apidoc to show.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.
* *`symbol`*: The symbol name to get apidocs for.

Return:

* list of apidocs or `nil`

- - -

<a id="get_class"></a>
### `get_class`(*sense, symbol*)

Returns the class name for *symbol* name.
If *symbol* is `sense.syntax.self` and inside a class definition matching
`sense.syntax.class_definition`, that class is returned. Otherwise the
buffer is searched backwards for a type declaration of *symbol* according to
the patterns in `sense.syntax.type_declarations` or a type assignment of
*symbol* according to `sense.syntax.type_assignments`.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.
* *`symbol`*: The symbol name to get the class of.

Return:

* class or `nil`

See also:

* [`syntax`](#syntax)

- - -

<a id="get_completions"></a>
### `get_completions`(*sense, symbol, only\_fields, only\_functions*)

Returns a list of function (unless *only_fields* is `true`) and field (unless
*only_funcs* is `true`) completions for *symbol* name.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.
* *`symbol`*: The symbol name to get completions for.
* *`only_fields`*: Optional flag indicating whether or not to return a list
  of only fields. The default value is `false`.
* *`only_functions`*: Optional flag indicating whether or not to return a
  list of only functions. The default value is `false`.

Return:

* completion_list or `nil`

- - -

<a id="get_symbol"></a>
### `get_symbol`(*sense*)

Returns a full symbol (if any) and current symbol part (if any) behind the
caret.
For example: `buffer.cur` would return `'buffer'` and `'cur'`. Returns empty
strings instead of `nil`.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.

Return:

* symbol or `''`
* part or `''`

- - -

<a id="goto_ctag"></a>
### `goto_ctag`(*sense, kind, title*)

Prompts the user to select a symbol to jump to from a list of all known
symbols of kind *kind* (classes, functions, fields, etc.) shown in a filtered
list dialog whose title text is *title*.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.
* *`kind`*: The Ctag character kind (e.g. `'f'` for a Lua function).
* *`title`*: The title for the filtered list dialog.

- - -

<a id="handle_clear"></a>
### `handle_clear`(*sense*)

Called when clearing the Adeptsense.
This function should be replaced with your own if you have any persistant
objects that need to be deleted.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.

- - -

<a id="handle_ctag"></a>
### `handle_ctag`(*sense, tag\_name, file\_name, ex\_cmd, ext\_fields*)

Called by `load_ctags()` when a Ctag kind is not recognized.
The parameters are extracted from Ctags' [tag format][]. This method should
be replaced with your own that is specific to the language.

[tag format]: http://ctags.sourceforge.net/ctags.html#TAG%20FILE%20FORMAT

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.
* *`tag_name`*: The tag name.
* *`file_name`*: The name of the file the tag belongs to.
* *`ex_cmd`*: The `ex_cmd` returned by Ctags.
* *`ext_fields`*: The `ext_fields` returned by Ctags.

- - -

<a id="load_ctags"></a>
### `load_ctags`(*sense, tag\_file, nolocations*)

Loads the Ctags file *tag_file* for autocompletions.
If *nolocations* is `true`, `sense:goto_ctag()` cannot be used with this set
of tags. It is recommended to pass `-n` to `ctags` in order to use line
numbers instead of text patterns to locate tags. This will greatly reduce
memory usage for a large number of symbols if `nolocations` is `false`.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`.
* *`tag_file`*: The path of the Ctags file to load.
* *`nolocations`*: Optional flag indicating whether or not to discard the
  locations of the tags for use by `sense:goto_ctag()`. The default value is
  `false`.

- - -

<a id="new"></a>
### `new`(*lang*)

Creates and returns a new Adeptsense for *lang* name.
Only one sense can exist per language.

Parameters:

* *`lang`*: The lexer language name to create an Adeptsense for.

Usage:

* `local lua_sense = _M.textadept.adeptsense.new('lua')`

Return:

* adeptsense

- - -

<a id="show_apidoc"></a>
### `show_apidoc`(*sense*)

Shows a call tip with API documentation for the symbol behind the caret.
If documentation is already being shown, cycles through multiple definitions.

Parameters:

* *`sense`*: The Adeptsense returned by `adeptsense.new()`. If `nil`, uses
  the current language's Adeptsense (if it exists).

Return:

* list of apidocs on success or `nil`.

See also:

* [`get_symbol`](#get_symbol)
* [`get_apidoc`](#get_apidoc)

- - -


## Tables

- - -

<a id="api_files"></a>
### `api_files`

A list of api files used by `show_apidoc()`.
Each line in the api file contains a symbol name (not the full symbol)
followed by a space character and then the symbol's documentation. Since
there may be many duplicate symbol names, it is recommended to put the full
symbol and arguments, if any, on the first line. (e.g. `Class.function(arg1,
arg2, ...)`). This allows the correct documentation to be shown based on the
current context. In the documentation, newlines are represented with "\n". A
'\' before "\n" escapes the newline.

- - -

<a id="completions"></a>
### `completions`

A list containing lists of possible completions for known symbols.
Each symbol key has a table value that contains a list of field completions
with a `fields` key and a list of functions completions with a `functions`
key. This table is normally populated by `load_ctags()`, but can also be set
by the user.

- - -

<a id="ctags_kinds"></a>
### `ctags_kinds`

A map of Ctags kinds to Adeptsense kinds.
Recognized kinds are `FUNCTION`, `FIELD`, and `CLASS`. Classes are quite
simply containers for functions and fields so Lua modules would count as
classes. Any other kinds will be passed to `handle_ctag()` for user-defined
handling.

Usage:

* `luasense.ctags_kinds = {f = _M.textadept.adeptsense.FUNCTION}`
* `csense.ctags_kinds = {m = _M.textadept.adeptsense.FIELD,
  f = _M.textadept.adeptsense.FUNCTION, c = _M.textadept.adeptsense.CLASS,
  s = _M.textadept.adeptsense.CLASS}`
* `javasense.ctags_kinds = {f = _M.textadept.adeptsense.FIELD,
  m = _M.textadept.adeptsense.FUNCTION, c = _M.textadept.adeptsense.CLASS,
  i = _M.textadept.adeptsense.CLASS}`

See also:

* [`handle_ctag`](#handle_ctag)

- - -

<a id="inherited_classes"></a>
### `inherited_classes`

A map of classes and a list of their inherited classes, normally populated by
`load_ctags()`.

- - -

<a id="locations"></a>
### `locations`

A list of the locations of known symbols, normally populated by
`load_ctags()`.

- - -

<a id="syntax"></a>
### `syntax`

Map of language-specific syntax settings.

Fields:

* `self`: The language's syntax-equivalent of `self`. The default value is
  `'self'`.
 * `class_definition`: A Lua pattern representing the language's class
  definition syntax. The first capture returned must be the class name. A
  second, optional capture contains the class' superclass (if any). If no
  completions are found for the class name, completions for the superclass
  are shown (if any). Completions will not be shown for both a class and
  superclass unless defined in a previously loaded Ctags file. Also, multiple
  superclasses cannot be recognized by this pattern; use a Ctags file
  instead. The default value is `'class%s+([%w_]+)'`.
 * `word_chars`: A Lua pattern of characters allowed in a word.
  The default value is `'%w_'`.
 * `symbol_chars`: A Lua pattern of characters allowed in a symbol,
  including member operators. The pattern should be a character set.
  The default value is `'[%w_%.]'`.
 * `type_declarations`: A list of Lua patterns used for determining the
  class type of a symbol. The first capture returned must be the class name.
  Use `%_` to match the symbol.
  The default value is `'(%u[%w_%.]+)%s+%_'`.
 * `type_declarations_exclude`: A table of types to exclude, even if they
  match a `type_declarations` pattern. Each excluded type is a table key and
  has a `true` boolean value. For example, `{Foo = true}` excludes any type
  whose name is `Foo`.
  The default value is `{}`.
 * `type_assignments`: A map of Lua patterns to class types for variable
  assignments, typically used for dynamically typed languages. For example,
  `sense.syntax.type_assignments['^"'] = 'string'`  would recognize string
  assignments in Lua so the `foo` in `foo = "bar"` would be recognized as
  type `string`. The class type value may contain `%n` pattern captures.
 
See also:

* [`get_class`](#get_class)

- - -

