// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using ICSharpCode.TextEditor; using ICSharpCode.TextEditor.Gui.CompletionWindow; using Languages.Facade; using PascalABCCompiler.Parsers; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace VisualPascalABC { public class CodeCompletionProvider : ICompletionDataProvider { public string preSelection; public static CodeCompletionImagesProvider ImagesProvider; public static DefaultDispatcher disp; public bool ByFirstChar; static CodeCompletionProvider() { ImagesProvider = new CodeCompletionImagesProvider(); disp = new DefaultDispatcher(); CodeCompletion.AssemblyDocCache.dispatcher = disp; CodeCompletion.UnitDocCache.dispatcher = disp; } public CodeCompletionProvider() { } public ImageList ImageList { get { return ImagesProvider.ImageList; } } public string PreSelection { get { return preSelection; } } public int DefaultIndex { get { return defaultIndex; } } public UserDefaultCompletionData DefaultCompletionElement { get { return defaultCompletionElement; } } private UserDefaultCompletionData defaultCompletionElement; private int defaultIndex = -1; public CompletionDataProviderKeyResult ProcessKey(char key) { if (char.IsLetterOrDigit(key) || key == '_') { return CompletionDataProviderKeyResult.NormalKey; } else { // key triggers insertion of selected items return CompletionDataProviderKeyResult.InsertionKey; } } /// /// Called when entry should be inserted. Forward to the insertion action of the completion data. /// public bool InsertAction(ICompletionData data, TextArea textArea, int insertionOffset, char key) { textArea.Caret.Position = textArea.Document.OffsetToPosition(insertionOffset); if (!(data as UserDefaultCompletionData).IsOnOverrideWindow) { int ind = data.Text.IndexOf('<'); if (ind != -1 && data.Text.Length > ind + 1 && data.Text[ind + 1] == '>') data.Text = data.Text.Substring(0, ind); } else data.Text = data.Description; return data.InsertAction(textArea, key); } public PascalABCCompiler.Parsers.KeywordKind keyword; public List GetDefinition(string expr, string fileName, int line, int column, bool only_check) { List Errors = new List(); PascalABCCompiler.SyntaxTree.expression e = null; List loc = null; ILanguage language = LanguageProvider.Instance.SelectLanguageByExtension(fileName); if (language == null) return null; if (VisualPABCSingleton.MainForm.VisualEnvironmentCompiler.compilerLoaded) e = language.Parser.GetExpression("test" + System.IO.Path.GetExtension(fileName), expr, Errors, new List()); if (e == null) return loc; CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName]; if (dconv == null) return loc; loc = dconv.GetDefinition(e, line, column, keyword, only_check); return loc; } private string construct_header(string meth, CodeCompletion.ProcScope ps, int tabCount) { //if (CodeCompletion.CodeCompletionController.currentParser != null) return CodeCompletion.CodeCompletionController.CurrentLanguage.LanguageIntellisenseSupport.ConstructHeader(meth, ps, tabCount); } private string construct_header(CodeCompletion.ProcRealization ps, int tabCount) { return CodeCompletion.CodeCompletionController.CurrentLanguage.LanguageIntellisenseSupport.ConstructHeader(ps, tabCount); } public CodeCompletion.SymScope FindScopeByLocation(string fileName, int line, int col) { CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName]; if (dconv == null) return null; return dconv.FindScopeByLocation(line, col); } public string GetMethodImplementationTextToAdd(string fileName, int line, int col, ref PascalABCCompiler.Parsers.Position pos, TextArea textArea) { CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName]; if (dconv == null) return null; CodeCompletion.ProcScope[] procs = dconv.GetNotImplementedMethodHeaders(line, col, ref pos); if (procs == null || procs.Length == 0) return null; System.Text.StringBuilder sb = new StringBuilder(); for (int i = 0; i < procs.Length; i++) { string meth = construct_header(procs[i] as CodeCompletion.ProcRealization, VisualPABCSingleton.MainForm.UserOptions.CursorTabCount); sb.Append(meth); //sb.Append('\n'); } return sb.ToString(); } public string GetRealizationTextToAdd(string fileName, int line, int col, ref PascalABCCompiler.Parsers.Position pos, TextArea textArea) { CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName]; if (dconv == null) return null; CodeCompletion.ProcScope[] procs = dconv.GetNotImplementedMethods(line, col, ref pos); if (procs == null) return null; System.Text.StringBuilder sb = new StringBuilder(); sb.Append("\n\n"); for (int i = 0; i < procs.Length; i++) { int off = textArea.Document.PositionToOffset(new TextLocation(procs[i].GetPosition().column - 1, procs[i].GetPosition().line - 1)); string meth = textArea.Document.GetText(off, textArea.Document.PositionToOffset(new TextLocation(procs[i].GetPosition().end_column - 1, procs[i].GetPosition().end_line - 1)) - off + 1); meth = construct_header(meth, procs[i], VisualPABCSingleton.MainForm.UserOptions.CursorTabCount); if (i < procs.Length - 1) { sb.Append(meth); sb.Append('\n'); } else sb.Append(meth.Trim()); } return sb.ToString(); } public List GetRealization(string expr, string fileName, int line, int column) { List Errors = new List(); PascalABCCompiler.SyntaxTree.expression e = null; List loc = null; if (VisualPABCSingleton.MainForm.VisualEnvironmentCompiler.compilerLoaded) e = LanguageProvider.Instance.SelectLanguageByExtensionSafe(fileName)?.Parser.GetExpression("test" + System.IO.Path.GetExtension(fileName), expr, Errors, new List()); if (e == null /*|| Errors.Count > 0*/) return loc; CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName]; if (dconv == null) return loc; loc = dconv.GetRealization(e, line, column, keyword); return loc; } private RenameForm rf; public List Rename(string expr, string name, string fileName, int line, int column) { List refers = FindReferences(expr, fileName, line, column, true); return refers; } public List Rename(string expr, string name, string fileName, int line, int column, ref string new_val) { if (rf == null) { rf = new RenameForm(); Form1StringResources.SetTextForAllControls(rf); } rf.EditValue = name.Trim(' ').Replace("&", ""); DialogResult dr = rf.ShowDialog(); if (dr == DialogResult.OK) { new_val = rf.EditValue; List refers = FindReferences(expr, fileName, line, column, true); if (refers == null) return null; return refers; } return null; } public List FindReferences(string expr, string fileName, int line, int column, bool for_refact) { List Errors = new List(); PascalABCCompiler.SyntaxTree.expression e = null; if (VisualPABCSingleton.MainForm.VisualEnvironmentCompiler.compilerLoaded) e = LanguageProvider.Instance.SelectLanguageByExtensionSafe(fileName)?.Parser.GetExpression("test" + System.IO.Path.GetExtension(fileName), expr, Errors, new List()); if (e == null) return new List(); CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName]; if (dconv == null) return new List(); List lst = InternalFindReferences(fileName, e, line, column, for_refact); //if (lst != null && expr != null && for_refact) //lst.Insert(0,new SymbolsViewerSymbol(new PascalABCCompiler.SourceLocation(file_name,line+1,column,line+1,column+expr.Length),ImagesProvider.IconNumberGotoText)); return lst; } private List InternalFindReferences(string fname, PascalABCCompiler.SyntaxTree.expression expr, int line, int col, bool for_refact) { List lst = new List(); List svs_lst = new List(); try { CodeCompletion.DomConverter dc = CodeCompletion.CodeCompletionController.comp_modules[fname] as CodeCompletion.DomConverter; IBaseScope fnd_scope = null; IBaseScope cur_sc = null; if (dc != null) { fnd_scope = dc.GetSymDefinition(expr, line, col, keyword); cur_sc = dc.FindScopeByLocation(line, col); } if (fnd_scope != null) { foreach (string FileName in CodeCompletionParserController.filesToParse.Keys) { CodeCompletion.CodeCompletionController controller = new CodeCompletion.CodeCompletionController(); string text = VisualPABCSingleton.MainForm.VisualEnvironmentCompiler.SourceFilesProvider(FileName, PascalABCCompiler.SourceFileOperation.GetText) as string; PascalABCCompiler.SyntaxTree.compilation_unit cu = controller.ParseOnlySyntaxTree(FileName, text); if (cu != null) { dc = CodeCompletion.CodeCompletionController.comp_modules[FileName] as CodeCompletion.DomConverter; CodeCompletion.ReferenceFinder rf = null; if (dc != null && dc.visitor.entry_scope != null) { rf = new CodeCompletion.ReferenceFinder(fnd_scope, dc.visitor.entry_scope, cu, FileName, for_refact); lst.AddRange(rf.FindPositions()); } } } PascalABCCompiler.Parsers.Position p = fnd_scope.GetPosition(); bool need_add_def = !for_refact; // true if (p.file_name != null && need_add_def) svs_lst.Add(new SymbolsViewerSymbol(new PascalABCCompiler.SourceLocation(p.file_name, p.line, p.column, p.end_line, p.end_column), ImagesProvider.GetPictureNum(fnd_scope.SymbolInfo))); foreach (PascalABCCompiler.Parsers.Position pos in lst) { if (pos.file_name != null) svs_lst.Add(new SymbolsViewerSymbol(new PascalABCCompiler.SourceLocation(pos.file_name, pos.line, pos.column, pos.end_line, pos.end_column), ImagesProvider.IconNumberGotoText)); } } } catch (Exception e) { } GC.Collect(); return svs_lst; //return svs_lst.ToArray(); } public string FindExpression(int off, string Text, int line, int col) { if (CodeCompletion.CodeCompletionController.IntellisenseAvailable()) return CodeCompletion.CodeCompletionController.CurrentLanguage.LanguageIntellisenseSupport.FindExpression(off, Text, line, col, out keyword); return null; } private string SkipNew(int off, string Text) { int tmp = off; string expr = null; while (off >= 0 && Char.IsLetterOrDigit(Text[off])) off--; while (off >= 0 && (Text[off] == ' ' || char.IsControl(Text[off]))) off--; if (off >= 1 && Text[off] == '=' && Text[off - 1] == ':') { off -= 2; while (off >= 0 && (Text[off] == ' ' || char.IsControl(Text[off]))) off--; if (off >= 0 && (Text[off] == '_' || char.IsLetterOrDigit(Text[off]) || Text[off] == ']')) expr = FindExpression(off + 1, Text, 0, 0); } return expr; } /// /// Возвращает подсказки определяемые первым символом выражения, введенного пользователем /// public ICompletionData[] GetCompletionDataByFirst(int line, int col, char charTyped, KeywordKind keyw) { List resultList = new List(); try { ILanguage currentLanguage = CodeCompletion.CodeCompletionController.CurrentLanguage; List keywords; bool isTypeAfterKeyword = false; // если по смыслу должен вводиться тип данных if (currentLanguage.LanguageIntellisenseSupport.IsTypeAfterKeyword(keyw)) { keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetTypeKeywords(); isTypeAfterKeyword = true; } else { keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords(); } bool isNamespaceAfterKeyword = false; // конструкция типа "uses" if (currentLanguage.LanguageIntellisenseSupport.IsNamespaceAfterKeyword(keyw)) { isNamespaceAfterKeyword = true; } else { resultList.AddRange(keywords.Select(keyword => new UserDefaultCompletionData(keyword, null, ImagesProvider.IconNumberKeyword, false))); } SymInfo[] symInfos = GetSymInfosForCompletionDataByFirst(line, col, isTypeAfterKeyword, isNamespaceAfterKeyword, charTyped.ToString()); if (symInfos != null) { currentLanguage.LanguageIntellisenseSupport.RenameOrExcludeSpecialNames(symInfos); AddCompletionDatasByFirstForSymInfos(resultList, charTyped, symInfos, currentLanguage.CaseSensitive); //resultList.Sort(); //defaultCompletionElement = resultList[0] as DefaultCompletionData; } } catch (Exception) { } this.ByFirstChar = true; return resultList.ToArray(); } /// /// Добавляет в resultList (итоговый список подсказок) данные, соответствующие переданному массиву типа SymInfo[]. /// Используется для случая ввода пользователем первого символа выражения /// private void AddCompletionDatasByFirstForSymInfos(List resultList, char charTyped, SymInfo[] symInfos, bool languageCaseSensitive) { HashSet symbolsAdded = languageCaseSensitive ? new HashSet() : new HashSet(StringComparer.CurrentCultureIgnoreCase); List candidatesForDefault = new List(); bool stop = false; ICompletionData lastUsedItem = CompletionDataDispatcher.GetLastUsedItem(charTyped); foreach (SymInfo symInfo in symInfos) { if (symInfo == null || symInfo.not_include) continue; string nameToShow = GetDisplayedName(symInfo); if (symbolsAdded.Contains(nameToShow + symInfo.kind)) continue; UserDefaultCompletionData completionData = new UserDefaultCompletionData(nameToShow, symInfo.description, ImagesProvider.GetPictureNum(symInfo), false); StringComparison stringComparison = languageCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase; // если мы выбирали что-то раньше из списка подсказок, то считаем это элементом по умолчанию if (!stop && lastUsedItem != null && string.Equals(nameToShow, lastUsedItem.Text, stringComparison)) { defaultCompletionElement = completionData; stop = true; } // иначе формируем список подходящих подсказок - "кандидатов" для элемента по умолчанию else if (!stop && lastUsedItem == null && nameToShow.StartsWith(charTyped.ToString(), stringComparison)) { //defaultCompletionElement = ddd; candidatesForDefault.Add(completionData); //stop = true; } disp.Add(symInfo, completionData); resultList.Add(completionData); symbolsAdded.Add(nameToShow + symInfo.kind); } if (candidatesForDefault.Count > 0) defaultCompletionElement = candidatesForDefault.Min() as UserDefaultCompletionData; // здесь выбирается минимальное по длине } /// /// Формирует массив данных из таблицы символов для подсказок в случае введения пользователем первой буквы выражения /// private SymInfo[] GetSymInfosForCompletionDataByFirst(int line, int col, bool isTypeAfterKeyword, bool isNamespaceAfterKeyword, string pattern) { CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[FileName]; /*if (dconv == null && CodeCompletion.CodeCompletionNameHelper.system_unit_file_full_name != null && (keyw == CodeCompletion.KeywordKind.kw_colon || keyw == CodeCompletion.KeywordKind.kw_of)) { dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[CodeCompletion.CodeCompletionNameHelper.system_unit_file_full_name]; special_module = true; }*/ SymInfo[] symInfos = null; if (dconv == null) { if (isNamespaceAfterKeyword) { symInfos = CodeCompletion.DomConverter.standard_units; } } else { //if (keyw == PascalABCCompiler.Parsers.KeywordKind.Colon || keyw == PascalABCCompiler.Parsers.KeywordKind.Of || keyw == PascalABCCompiler.Parsers.KeywordKind.TypeDecl) if (isTypeAfterKeyword) { symInfos = dconv.GetTypeByPattern(pattern, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange); } else if (isNamespaceAfterKeyword) { if (WorkbenchServiceFactory.Workbench.UserOptions.EnableSmartIntellisense) symInfos = dconv.GetNamespaces(); else symInfos = CodeCompletion.DomConverter.standard_units; } else { // интересно, что передается pattern = null EVA symInfos = dconv.GetNameByPattern(null, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange); } } return symInfos; } /// /// Вспомогательная струтура для метода GetCompletionData, хранит информацию о действиях пользователя /// private struct ActionContext { public bool dotPressed; public bool ctrlSpace; public bool shiftSpace; public bool spaceAfterNew; public bool spaceAfterUses; } /// /// Возвращает массив подсказок для случая нажатия пользователем "триггерной" клавиши /// public ICompletionData[] GetCompletionData(int off, string text, int line, int col, char charTyped, KeywordKind keywordKind) { List resultList = new List(); try { // поменять на обращение к CodeCompletionController.CurrentLanguage ILanguage currentLanguage = LanguageProvider.Instance.SelectLanguageByExtension(FileName); var context = new ActionContext() { dotPressed = charTyped == '.', ctrlSpace = charTyped == '_', shiftSpace = charTyped == '\0', spaceAfterNew = keywordKind == KeywordKind.New, spaceAfterUses = keywordKind == KeywordKind.Uses }; string expressionText = GetExpressionTextForCompletionData(off, text, line, col, currentLanguage.LanguageIntellisenseSupport, in context, out var insidePatternWithDots, out var ctrlOrShiftSpaceAfterDot, out var pattern); // добавляем ключевые слова в случае "ctrl + space", нажатых в "пустом" месте if (!ctrlOrShiftSpaceAfterDot && context.ctrlSpace && string.IsNullOrEmpty(pattern)) { var keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords(); resultList.AddRange(keywords.Select(keyword => new UserDefaultCompletionData(keyword, null, ImagesProvider.IconNumberKeyword, false))); } PascalABCCompiler.SyntaxTree.expression expr = null; // для "ctrl + space" и "shift + space" дерево expression не требуется (кроме случая insidePatternWithDots) if ((context.dotPressed || context.spaceAfterNew || context.spaceAfterUses || insidePatternWithDots) && expressionText != null) { expr = GetExpressionForCompletionData(currentLanguage.Parser, in context, expressionText, insidePatternWithDots, out var shouldReturnNull); if (shouldReturnNull) return null; } SymInfo[] symInfos = GetSymInfosForCompletionData(line, col, in context, currentLanguage.CaseSensitive, expressionText, ctrlOrShiftSpaceAfterDot, insidePatternWithDots, pattern, expr, out var selectedSymInfo, out var lastUsedMember, out var shouldReturnNull2); if (shouldReturnNull2) return null; if (symInfos != null) { currentLanguage.LanguageIntellisenseSupport.RenameOrExcludeSpecialNames(symInfos); AddCompletionDatasForSymInfos(resultList, currentLanguage.CaseSensitive, symInfos, selectedSymInfo, lastUsedMember); } } catch (Exception) { } return resultList.ToArray(); } /// /// Добавляет в resultList (итоговый список подсказок) данные, соответствующие переданному массиву типа SymInfo[]. /// Используется для случая нажатия пользователем "триггерной" клавиши /// private void AddCompletionDatasForSymInfos(List resultList, bool languageCaseSensitive, SymInfo[] symInfos, SymInfo selectedSymInfo, string lastUsedMember) { // ICompletionData data = null; HashSet symbolsAdded = languageCaseSensitive ? new HashSet() : new HashSet(StringComparer.CurrentCultureIgnoreCase); foreach (SymInfo symInfo in symInfos) { if (symInfo == null || symInfo.not_include) continue; string nameToShow = GetDisplayedName(symInfo); if (symbolsAdded.Contains(nameToShow + symInfo.kind)) continue; UserDefaultCompletionData completionData = new UserDefaultCompletionData(nameToShow, symInfo.description, ImagesProvider.GetPictureNum(symInfo), false); disp.Add(symInfo, completionData); resultList.Add(completionData); symbolsAdded.Add(nameToShow + symInfo.kind); /*if (VisualPABCSingleton.MainForm.UserOptions.EnableSmartIntellisense && mi.name != null && mi.name != "" && data == null) { data = CompletionDataDispatcher.GetLastUsedItem(mi.name[0]); if (data != null && data.Text == ddd.Text) data = ddd; }*/ if (lastUsedMember != null && lastUsedMember == nameToShow || selectedSymInfo != null && symInfo == selectedSymInfo) { defaultCompletionElement = completionData; } } /*if (defaultCompletionElement == null && data != null) defaultCompletionElement = data as UserDefaultCompletionData;*/ } /// /// Формирует массив данных из таблицы символов для подсказок в случае нажатия пользователем "триггерной" клавиши /// (в зависимости от введенного выражения и другого контекста) /// private SymInfo[] GetSymInfosForCompletionData(int line, int col, in ActionContext context, bool languageCaseSensitive, string expressionText, bool ctrlOrShiftSpaceAfterDot, bool insidePatternWithDots, string pattern, PascalABCCompiler.SyntaxTree.expression expr, out SymInfo selectedSymInfo, out string lastUsedMember, out bool shouldReturnNull) { SymInfo[] symInfos = null; shouldReturnNull = false; selectedSymInfo = null; lastUsedMember = null; CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[FileName]; if (dconv == null) { // в данном случае возвращаем пустой массив ICompletionData if (!context.spaceAfterUses && !context.ctrlSpace) shouldReturnNull = true; if (context.spaceAfterUses) symInfos = CodeCompletion.DomConverter.standard_units; } else { if (context.spaceAfterNew) { symInfos = dconv.GetTypes(expr, line, col, out selectedSymInfo); } else if (context.spaceAfterUses) { if (WorkbenchServiceFactory.Workbench.UserOptions.EnableSmartIntellisense) symInfos = dconv.GetNamespaces(); else symInfos = CodeCompletion.DomConverter.standard_units; } // нажатие ctrl + space и shift + space сразу после точки приравнивается к нажатию точки else if (context.dotPressed || ctrlOrShiftSpaceAfterDot) { CodeCompletion.SymScope dotScope = null; symInfos = dconv.GetName(expr, expressionText, line, col, keyword, ref dotScope); if (dotScope != null && VisualPABCSingleton.MainForm.UserOptions.EnableSmartIntellisense) { CompletionDataDispatcher.AddMemberBeforeDot(dotScope); lastUsedMember = CompletionDataDispatcher.GetRecentUsedMember(dotScope); } } // ctrl + space или shift + space else if (context.ctrlSpace || context.shiftSpace) { CodeCompletion.SymScope dotScope = null; // если мы в цепочечном выражении с точками if (insidePatternWithDots) { symInfos = dconv.GetName(expr, expressionText, line, col, keyword, ref dotScope) .Where(symInfo => symInfo.name.StartsWith(pattern, languageCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)) .ToArray(); } else symInfos = dconv.GetNameByPattern(pattern, line, col, context.ctrlSpace, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange); } } return symInfos; } /// /// Возвращает дерево выражения, введенного пользователем перед нажатием "триггерной" клавиши /// private PascalABCCompiler.SyntaxTree.expression GetExpressionForCompletionData(IParser parser, in ActionContext context, string expressionText, bool insidePatternWithDots, out bool shouldReturnNull) { shouldReturnNull = false; List Errors = new List(); List Warnings = new List(); var expr = parser.GetTypeAsExpression("test" + System.IO.Path.GetExtension(FileName), expressionText, Errors, Warnings); if (expr == null) { Errors.Clear(); expr = parser.GetExpression("test" + System.IO.Path.GetExtension(FileName), expressionText, Errors, Warnings); } if ((expr == null || Errors.Count > 0) && !context.spaceAfterNew) shouldReturnNull = true; return expr; } /// /// Получение текста выражения, введенного пользователем перед нажатием "триггерной" клавиши /// private string GetExpressionTextForCompletionData(int off, string text, int line, int col, ILanguageIntellisenseSupport languageIntellisenseSupport, in ActionContext context, out bool insidePatternWithDots, out bool ctrlOrShiftSpaceAfterDot, out string pattern) { string expressionText = null; pattern = null; insidePatternWithDots = false; ctrlOrShiftSpaceAfterDot = false; if (context.ctrlSpace || context.shiftSpace) { pattern = languageIntellisenseSupport.FindPattern(off, text, out var isPattern); // в конце выражения точка if (!isPattern && text[off - 1] == '.') { ctrlOrShiftSpaceAfterDot = true; } // если нужно подсказать все варианты после точки, то поведение как в случае context.dotPressed if (isPattern && text[off - pattern.Length - 1] == '.' || ctrlOrShiftSpaceAfterDot) { insidePatternWithDots = true; expressionText = FindExpression(off - (pattern?.Length ?? 0) - 1, text, line, col); } } else if (context.spaceAfterNew) { expressionText = languageIntellisenseSupport.SkipNew(off - 1, text, ref keyword); } else if (context.dotPressed) // keywordKind != KeywordKind.Uses { expressionText = FindExpression(off, text, line, col); } return expressionText; } private CodeCompletion.CodeCompletionController controller; private string FileName; private string Text; public void CompileInThread() { controller.Compile(FileName, Text /*+ ")))));end."*/); } public ICompletionData[] ddata; public ICompletionData[] GenerateCompletionDataWithKeyword(string fileName, TextArea textArea, char charTyped, PascalABCCompiler.Parsers.KeywordKind keyw) { controller = new CodeCompletion.CodeCompletionController(); int off = textArea.Caret.Offset; string text = textArea.Document.TextContent.Substring(0, textArea.Caret.Offset); //controller.Compile(file_name, text /*+ ")))));end."*/); FileName = fileName; Text = text; ICompletionData[] data = GetCompletionData(off, text, textArea.Caret.Line, textArea.Caret.Column, charTyped, keyw); CodeCompletion.AssemblyDocCache.CompleteDocumentation(); CodeCompletion.UnitDocCache.CompleteDocumentation(); controller = null; //GC.Collect(); return data; } public ICompletionData[] GenerateCompletionData(string fileName, TextArea textArea, char charTyped) { return null; } public ICompletionData[] GenerateCompletionDataForOverridableMethods(string fileName, TextArea textArea) { controller = new CodeCompletion.CodeCompletionController(); List lst = new List(); int line = textArea.Caret.Line; int col = textArea.Caret.Column; try { CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName]; SymInfo[] mis = null; if (dconv != null) { mis = dconv.GetOverridableMethods(line, col); } if (mis != null) { foreach (SymInfo mi in mis) { UserDefaultCompletionData ddd = new UserDefaultCompletionData(mi.name, mi.description, ImagesProvider.GetPictureNum(mi), true); lst.Add(ddd); } } } catch (Exception e) { } //lst.Sort(); ICompletionData[] res_arr = lst.ToArray(); controller = null; return res_arr; } public ICompletionData[] GenerateCompletionDataByFirstChar(string fileName, TextArea textArea, char charTyped, PascalABCCompiler.Parsers.KeywordKind keyw) { controller = new CodeCompletion.CodeCompletionController(); // int off = textArea.Caret.Offset; string text = textArea.Document.TextContent.Substring(0, textArea.Caret.Offset); //controller.Compile(file_name, text /*+ ")))));end."*/); FileName = fileName; Text = text; ICompletionData[] data = GetCompletionDataByFirst(textArea.Caret.Line, textArea.Caret.Column, charTyped, keyw); CodeCompletion.AssemblyDocCache.CompleteDocumentation(); CodeCompletion.UnitDocCache.CompleteDocumentation(); controller = null; //GC.Collect(); return data; } private string GetDisplayedName(SymInfo symInfo) { if (symInfo.aliasName != null) return symInfo.aliasName; if (symInfo.addit_name != null) return symInfo.addit_name; return symInfo.name; } } }