public static bool IsCompletionAllowed(IEditorData Editor, char enteredChar) { if (Editor.CaretOffset > 0) { if (Editor.CaretLocation.Line == 1 && Editor.ModuleCode.Length > 0 && Editor.ModuleCode[0] == '#') { return(false); } if (enteredChar == '.' || enteredChar == '_') { // Don't complete on a double/multi-dot if (Editor.CaretOffset > 1 && Editor.ModuleCode[Editor.CaretOffset - 2] == enteredChar) { // ISSUE: When a dot was typed, off-1 is the dot position, // if a letter was typed, off-1 is the char before the typed letter.. return(false); } } // If typing a begun identifier, return immediately else if ((DTokens.IsIdentifierChar(enteredChar) || enteredChar == '\0') && DTokens.IsIdentifierChar(Editor.ModuleCode[Editor.CaretOffset - 1])) { return(false); } return(!CaretContextAnalyzer.IsInCommentAreaOrString(Editor.ModuleCode, Editor.CaretOffset)); } return(true); }
static bool IsCompletionAllowed(IEditorData Editor, string EnteredText) { // If typing a begun identifier, return immediately if ((EnteredText != null && EnteredText.Length > 0 ? IsIdentifierChar(EnteredText[0]) : true) && Editor.CaretOffset > 0 && IsIdentifierChar(Editor.ModuleCode[Editor.CaretOffset - 1])) { return(false); } if (CaretContextAnalyzer.IsInCommentAreaOrString(Editor.ModuleCode, Editor.CaretOffset)) { return(false); } return(true); }
/// <summary> /// Reparses the code of the current scope and returns the object (either IExpression or ITypeDeclaration derivative) /// that is beneath the caret location. /// /// Used for code completion/symbol resolution. /// Mind the extra options that might be passed via the Options parameter. /// </summary> /// <param name="ctxt">Can be null</param> public static ISyntaxRegion GetScopedCodeObject(IEditorData editor, ResolverContextStack ctxt = null, AstReparseOptions Options = 0) { if (ctxt == null) { ctxt = ResolverContextStack.Create(editor); } var code = editor.ModuleCode; int start = 0; var startLocation = CodeLocation.Empty; bool IsExpression = false; if (ctxt.CurrentContext.ScopedStatement is IExpressionContainingStatement) { var exprs = ((IExpressionContainingStatement)ctxt.CurrentContext.ScopedStatement).SubExpressions; IExpression targetExpr = null; if (exprs != null) { foreach (var ex in exprs) { if ((targetExpr = ExpressionHelper.SearchExpressionDeeply(ex, editor.CaretLocation, true)) != ex) { break; } } } if (targetExpr != null && editor.CaretLocation >= targetExpr.Location && editor.CaretLocation <= targetExpr.EndLocation) { startLocation = targetExpr.Location; start = DocumentHelper.LocationToOffset(editor.ModuleCode, startLocation); IsExpression = true; } } if (!IsExpression) { // First check if caret is inside a comment/string etc. int lastStart = -1; int lastEnd = -1; var caretContext = CaretContextAnalyzer.GetTokenContext(code, editor.CaretOffset, out lastStart, out lastEnd); // Return if comment etc. found if (caretContext != TokenContext.None) { return(null); } start = CaretContextAnalyzer.SearchExpressionStart(code, editor.CaretOffset - 1, (lastEnd > 0 && lastEnd < editor.CaretOffset) ? lastEnd : 0); startLocation = DocumentHelper.OffsetToLocation(editor.ModuleCode, start); } if (start < 0 || editor.CaretOffset <= start) { return(null); } var expressionCode = code.Substring(start, Options.HasFlag(AstReparseOptions.AlsoParseBeyondCaret) ? code.Length - start : editor.CaretOffset - start); var parser = DParser.Create(new StringReader(expressionCode)); parser.Lexer.SetInitialLocation(startLocation); parser.Step(); if (!IsExpression && Options.HasFlag(AstReparseOptions.OnlyAssumeIdentifierList) && parser.Lexer.LookAhead.Kind == DTokens.Identifier) { return(parser.IdentifierList()); } else if (IsExpression || parser.IsAssignExpression()) { if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression)) { return(parser.AssignExpression()); } else { return(ExpressionHelper.SearchExpressionDeeply(parser.AssignExpression(), editor.CaretLocation, Options.HasFlag(AstReparseOptions.WatchForParamExpressions))); } } else { return(parser.Type()); } }
/// <summary> /// Reparses the code of the current scope and returns the object (either IExpression or ITypeDeclaration derivative) /// that is beneath the caret location. /// /// Used for code completion/symbol resolution. /// Mind the extra options that might be passed via the Options parameter. /// </summary> /// <param name="ctxt">Can be null</param> public static ISyntaxRegion GetScopedCodeObject(IEditorData editor, AstReparseOptions Options = AstReparseOptions.AlsoParseBeyondCaret, ResolutionContext ctxt = null) { if (ctxt == null) { ctxt = ResolutionContext.Create(editor); } var code = editor.ModuleCode; int start = 0; var startLocation = CodeLocation.Empty; bool IsExpression = false; if (ctxt.CurrentContext.ScopedStatement is IExpressionContainingStatement) { var exprs = ((IExpressionContainingStatement)ctxt.CurrentContext.ScopedStatement).SubExpressions; IExpression targetExpr = null; if (exprs != null) { foreach (var ex in exprs) { if ((targetExpr = ExpressionHelper.SearchExpressionDeeply(ex, editor.CaretLocation)) != ex) { break; } } } if (targetExpr != null && editor.CaretLocation >= targetExpr.Location && editor.CaretLocation <= targetExpr.EndLocation) { startLocation = targetExpr.Location; start = DocumentHelper.GetOffsetByRelativeLocation(editor.ModuleCode, editor.CaretLocation, editor.CaretOffset, startLocation); IsExpression = true; } } if (!IsExpression) { // First check if caret is inside a comment/string etc. int lastStart = 0; int lastEnd = 0; if ((Options & AstReparseOptions.DontCheckForCommentsOrStringSurrounding) == 0) { var caretContext = CaretContextAnalyzer.GetTokenContext(code, editor.CaretOffset, out lastStart, out lastEnd); // Return if comment etc. found if (caretContext != TokenContext.None) { return(null); } } // Could be somewhere in an ITypeDeclaration.. if (editor.CaretOffset < 0 || editor.CaretOffset >= code.Length) { return(null); } if (Lexer.IsIdentifierPart(code[editor.CaretOffset])) { start = editor.CaretOffset; } else if (editor.CaretOffset > 0 && Lexer.IsIdentifierPart(code[editor.CaretOffset - 1])) { start = editor.CaretOffset - 1; } start = CaretContextAnalyzer.SearchExpressionStart(code, start, (lastEnd > 0 && lastEnd < editor.CaretOffset) ? lastEnd : 0); startLocation = DocumentHelper.OffsetToLocation(editor.ModuleCode, start); } if (start < 0 || editor.CaretOffset < start) { return(null); } var sv = new StringView(code, start, Options.HasFlag(AstReparseOptions.AlsoParseBeyondCaret) ? code.Length - start : editor.CaretOffset - start); var parser = DParser.Create(sv); parser.Lexer.SetInitialLocation(startLocation); parser.Step(); ITypeDeclaration td; if (!IsExpression && Options.HasFlag(AstReparseOptions.OnlyAssumeIdentifierList) && parser.Lexer.LookAhead.Kind == DTokens.Identifier) { td = parser.IdentifierList(); } else if (IsExpression || parser.IsAssignExpression()) { if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression)) { return(parser.AssignExpression()); } else { return(ExpressionHelper.SearchExpressionDeeply(parser.AssignExpression(), editor.CaretLocation)); } } else { td = parser.Type(); } if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression)) { return(td); } while (td != null && td.InnerDeclaration != null && editor.CaretLocation <= td.InnerDeclaration.EndLocation) { td = td.InnerDeclaration; } return(td); }
public override bool KeyPress(Gdk.Key key, char keyChar, Gdk.ModifierType modifier) { bool skipFormatting = StateTracker.Engine.IsInsideCommentOrString || StateTracker.Engine.IsInsidePreprocessorDirective; cursorPositionBeforeKeyPress = textEditorData.Caret.Offset; if (keyChar == ';' && !(textEditorData.CurrentMode is TextLinkEditMode)) { DoInsertTemplate(); } if (key == Gdk.Key.Tab) { stateTracker.UpdateEngine(); if (stateTracker.Engine.IsInsideStringLiteral && !textEditorData.IsSomethingSelected) { var tokenCtxt = CaretContextAnalyzer.GetTokenContext(textEditorData.Document.Text, textEditorData.Caret.Offset); if (tokenCtxt == TokenContext.String || tokenCtxt == TokenContext.VerbatimString) { textEditorData.InsertAtCaret("\\t"); return(false); } } } if (key == Gdk.Key.Tab && DefaultSourceEditorOptions.Instance.TabIsReindent && !CompletionWindowManager.IsVisible && !(textEditorData.CurrentMode is TextLinkEditMode) && !DoInsertTemplate() && !textEditorData.IsSomethingSelected) { int cursor = textEditorData.Caret.Offset; if (stateTracker.Engine.IsInsideVerbatimString && cursor > 0 && cursor < textEditorData.Document.TextLength && textEditorData.GetCharAt(cursor - 1) == '"') { stateTracker.UpdateEngine(cursor + 1); } if (stateTracker.Engine.IsInsideVerbatimString) { // insert normal tab inside r" ... " if (textEditorData.IsSomethingSelected) { textEditorData.SelectedText = "\t"; } else { textEditorData.Insert(cursor, "\t"); } textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } else if (cursor >= 1) { if (textEditorData.Caret.Column > 1) { int delta = cursor - this.cursorPositionBeforeKeyPress; if (delta < 2 && delta > 0) { textEditorData.Remove(cursor - delta, delta); textEditorData.Caret.Offset = cursor - delta; textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } } stateTracker.UpdateEngine(); DoReSmartIndent(); } return(false); } //do the smart indent if (textEditorData.Options.IndentStyle == IndentStyle.Smart || textEditorData.Options.IndentStyle == IndentStyle.Virtual) { bool retval; //capture some of the current state int oldBufLen = textEditorData.Length; int oldLine = textEditorData.Caret.Line + 1; bool hadSelection = textEditorData.IsSomethingSelected; bool reIndent = false; //pass through to the base class, which actually inserts the character //and calls HandleCodeCompletion etc to handles completion using (var undo = textEditorData.OpenUndoGroup()) { DoPreInsertionSmartIndent(key); } bool automaticReindent; using (var undo = textEditorData.OpenUndoGroup()) { retval = base.KeyPress(key, keyChar, modifier); //handle inserted characters if (textEditorData.Caret.Offset <= 0 || textEditorData.IsSomethingSelected) { return(retval); } lastCharInserted = TranslateKeyCharForIndenter(key, keyChar, textEditorData.GetCharAt(textEditorData.Caret.Offset - 1)); if (lastCharInserted == '\0') { return(retval); } stateTracker.UpdateEngine(); if (key == Gdk.Key.Return && modifier == Gdk.ModifierType.ControlMask) { FixLineStart(textEditorData.Caret.Line + 1); } else { if (!(oldLine == textEditorData.Caret.Line + 1 && lastCharInserted == '\n') && (oldBufLen != textEditorData.Length || lastCharInserted != '\0')) { DoPostInsertionSmartIndent(lastCharInserted, hadSelection, out reIndent); } } //reindent the line after the insertion, if needed //N.B. if the engine says we need to reindent, make sure that it's because a char was //inserted rather than just updating the stack due to moving around stateTracker.UpdateEngine(); automaticReindent = (stateTracker.Engine.NeedsReindent && lastCharInserted != '\0'); if (key == Gdk.Key.Return && (reIndent || automaticReindent)) { DoReSmartIndent(); } } if (key != Gdk.Key.Return && (reIndent || automaticReindent)) { using (var undo = textEditorData.OpenUndoGroup()) { DoReSmartIndent(); } } if (!skipFormatting && keyChar == '}') { using (var undo = textEditorData.OpenUndoGroup()) { RunFormatter(new DocumentLocation(textEditorData.Caret.Location.Line, textEditorData.Caret.Location.Column)); } } stateTracker.UpdateEngine(); lastCharInserted = '\0'; return(retval); } if (textEditorData.Options.IndentStyle == IndentStyle.Auto && DefaultSourceEditorOptions.Instance.TabIsReindent && key == Gdk.Key.Tab) { bool retval = base.KeyPress(key, keyChar, modifier); DoReSmartIndent(); return(retval); } //pass through to the base class, which actually inserts the character //and calls HandleCodeCompletion etc to handles completion var result = base.KeyPress(key, keyChar, modifier); if (!skipFormatting && keyChar == '}') { RunFormatter(new DocumentLocation(textEditorData.Caret.Location.Line, textEditorData.Caret.Location.Column)); } return(result); }
public override bool KeyPress(Key key, char keyChar, ModifierType modifier) { var ed = Document.Editor; var dPolicy = Document.HasProject ? Document.Project.Policies.Get <DFormattingPolicy> ("text/x-d") : PolicyService.GetDefaultPolicy <DFormattingPolicy> ("text/x-d"); if (key == Key.Return) { ed.DeleteSelectedText(true); int lastBegin; int lastEnd; var caretCtxt = CaretContextAnalyzer.GetTokenContext(ed.Text, ed.Caret.Offset, out lastBegin, out lastEnd); if (lastBegin >= 0 && (caretCtxt == TokenContext.BlockComment || caretCtxt == TokenContext.NestedComment)) { var charsToInsert = " " + (caretCtxt == TokenContext.BlockComment ? '*' : '+') + " "; var commentBeginIndent = ed.GetLineIndent(ed.GetLineByOffset(lastBegin)); ed.InsertAtCaret( Document.Editor.EolMarker + commentBeginIndent + (dPolicy.InsertStarAtCommentNewLine ? charsToInsert : "")); return(false); } } if (Document.Editor.Options.IndentStyle == IndentStyle.Smart || Document.Editor.Options.IndentStyle == IndentStyle.Virtual) { int newIndentation = 0; if (key == Key.Return) { ed.InsertAtCaret(Document.Editor.EolMarker); var tr = ed.Document.CreateReader(); var cb = DCodeFormatter.NativeFormatterInstance.CalculateIndentation(tr, ed.Caret.Line); tr.Close(); newIndentation = cb == null ? 0 : cb.GetLineIndentation(ed.Caret.Line); ed.InsertAtCaret(CalculateIndentationString(newIndentation)); return(false); } else if (keyChar == '{' || keyChar == '}' || keyChar == ':') { ed.DeleteSelectedText(true); ed.InsertAtCaret(keyChar.ToString()); // Ensure that we aren't in a non-code area right now - automatically trying to format comments is awful int lastBegin; int lastEnd; var caretCtxt = CaretContextAnalyzer.GetTokenContext(ed.Text, ed.Caret.Offset, out lastBegin, out lastEnd); if (lastBegin >= 0 && caretCtxt != TokenContext.None) { return(false); } var origInd = ed.GetLineIndent(ed.Caret.Line); int originalIndentation = origInd.Length; var tr = ed.Document.CreateReader(); var cb = DCodeFormatter.NativeFormatterInstance.CalculateIndentation(tr, ed.Caret.Line); tr.Close(); newIndentation = cb == null ? 0 : cb.GetLineIndentation(ed.Caret.Line); var newInd = CalculateIndentationString(newIndentation); if (origInd != newInd) { ed.Replace( Document.Editor.GetLine(ed.Caret.Line).Offset, originalIndentation, newInd); } return(false); } } return(base.KeyPress(key, keyChar, modifier)); }