[Mono-dev] csharp tab completion.

Miguel de Icaza miguel at novell.com
Thu Mar 12 12:51:47 EDT 2009


Hello,

    I cooked this patch on my last trip and just got it polished enough
that it is worth posting to the mailing list.

    A feature frequently requested is for the `csharp' interactive shell
is to provide bash-like tab completion so that you can quickly explore
the API without having to look things up.    The getline.cs library
already provided a mechanism for doing tab completion, but the support
was not implemented.

    The challenge was to reuse the current gmcs parser without having to
dramatically modify it and still provide completions.   The support
works like this.

    The parser and tokenizer work together so that the tokenizer upon
reaching the end of the input generates the following tokens:
GENERATE_COMPLETION followed by as many COMPLETE_COMPLETION token and
finally the EOF token.

    GENERATE_COMPLETION needs to be handled in every production where
the user is likely to press the TAB key in the shell (or in the future
the GUI, or an explicit request in an IDE).   COMPLETE_COMPLETION must
be handled throughout the grammar to provide a way of completing the
parsed expression.  See below for details. 

    For the member access case, I have added productions that mirror the
non-completing productions, for example:

  primary_expression DOT IDENTIFIER GENERATE_COMPLETION 
  {
	LocatedToken lt = (LocatedToken) $3;
	$$ = new CompletionMemberAccess ((Expression) $1, lt.Value, lt.Location);
  }

This mirrors:

  primary_expression DOT IDENTIFIER opt_type_argument_list
  {
	LocatedToken lt = (LocatedToken) $3;
	$$ = new MemberAccess ((Expression) $1, lt.Value, (TypeArguments) $4, lt.Location);
  }

   The CompletionMemberAccess is a new kind of Mono.CSharp.Expression
that does the actual lookup.   It internally mimics some of the
MemberAccess code but has been tuned for this particular use.

   After this initial token is processed GENERATE_COMPLETION the
tokenizer will emit COMPLETE_COMPLETION tokens.   This is done to help
the parser basically produce a valid result from the partial input it
received.    For example it is able to produce a valid AST from "(x"
even if no parenthesis has been closed.   This is achieved by sprinkling
the grammar with productions that can cope with this "winding down"
token, for example this is what parenthesized_expression looks like now:

parenthesized_expression
	: OPEN_PARENS expression CLOSE_PARENS
	  {
		$$ = new ParenthesizedExpression ((Expression) $2);
	  }
	//
	// New production
	//
	| OPEN_PARENS expression COMPLETE_COMPLETION
	  {
		$$ = new ParenthesizedExpression ((Expression) $2);
	  }
	;

    Once we have wrapped up everything we generate the last EOF token.

    When the AST is complete we actually trigger the regular semantic
analysis process.   The DoResolve method of each node in our abstract
syntax tree will compute the result and communicate the possible
completions by throwing an exception of type CompletionResult.

    This is the bit that I am not very comfortable with, I had to
provide both the prefix string and the results to allow the completion
engine to render things properly.

    So for example if the user type "T" and the completion is "ToString"
we return "oString".

    Attached is the patch for review.

Future Work:

    I have only implemented support for completion right now in two
spots: declared variables and member access, so stuff like foo.<TAB>
will produce the completions for foo properly and foo.T<TAB> will
produce the completions for anything in foo that starts with a T.   

    There are many other places missing (using declarations, type
parameters for example, and I am sure there are many other opportunities
missing), I might add those in the future if there is enough interest,
or even better, you can get yourself started with compiler technology
and email us patches ;-)

GSharp:

    The GUI version perhaps needs to implement this in a GUI-ish way
when the user presses a dot for example, or when the user presses a
hotkey.   The GUI version also has the benefit that it can distinguish
the user pressing tab from the user pasting some text with a tab.
 
Miguel

-------------- next part --------------
A non-text attachment was scrubbed...
Name: auto-complete-csharp
Type: text/x-patch
Size: 22688 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20090312/22213c6b/attachment-0001.bin 


More information about the Mono-devel-list mailing list