Refactor intellisense (#3213)

* Refactor keywords managing to avoid repeating them twice

* Fix build error

* Fix string comparisons and null reference exception

* Manage references in PascalABCLanguageInfo project

* Fix inaccuracy in BaseKeywords.cs

* Move ValidDirectives field to ILanguageInformation

* Basic refactoring of GetPopupHintText + delete ampersend inserting

* Delete other cases of ampersend inserting

* Add check that we parsing PascalABC.NET in GetPopupHintText

Временное решение, нужно будет вынести вторую попытку в интерфейс парсера.

* Refactor CodeCompletionProvider (first iteration)

* Extract shift space actions in separate class

* Replace dollar service character in CodeCompletion by separate boolean (ctrlSpaceAfterDot))

* Refactor GetCompletionDataByFirst method

* Fix GetCompletionDataByFirst behaviour when getting symInfos after uses keyword

* Another iteration of refactoring in CodeCompletionProvider + comments

* Update intellisense documentation

* Fix build error

* Fix encoding

* Squashed commit of the following:

commit 7751fe7e75
Author: samuraiGH <87191377+samuraiGH@users.noreply.github.com>
Date:   Sun Mar 16 13:28:03 2025 +0300

    generating language res file at build time (#3252)

commit d1fce63d69
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Mar 4 08:38:09 2025 +0300

    Сборка после pr SDK

commit d491e88aa7
Author: samuraiGH <87191377+samuraiGH@users.noreply.github.com>
Date:   Mon Mar 3 20:34:51 2025 +0300

    migration to new build system (#3241)

    * converting project files into sdk style
    * new build commands
    * adding new dll into nsis
    * removing unused .cs files

commit 1fd348ec3c
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sun Feb 23 20:49:26 2025 +0300

    NSIS New 3.10

    Ярлык в меню Пуск у всех пользователей

commit 80b7182dc1
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Feb 19 11:50:00 2025 +0300

    _ in names

commit a2b078960b
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Feb 19 10:52:25 2025 +0300

    cnfc2

commit 58f26d469d
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Feb 18 22:28:13 2025 +0300

    перекомпиляция 3.10.3.3611

commit b78a72977f
Author: nevermind322 <81963698+nevermind322@users.noreply.github.com>
Date:   Tue Feb 18 22:02:19 2025 +0300

    fix build on mono (#3249)

    * fix build on mono

    * remove local func

    * fix again

commit c3557e388c
Author: Nikolay Kuznetsov <adasoft@gmail.com>
Date:   Sat Feb 15 20:32:46 2025 +0300

    Update GraphABC.pas (#3244)

    1. Быстрая реализация функции FloodFill
    Для этого добавлена процедура BitmapFloodFill, которая вызывается из метода Picture.FloodFill и процедуры FloodFill

    2.Добавлена поддержка LockDrawing/UnlockDrawing в процедуру FloodFill

commit 9dbac389e1
Author: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com>
Date:   Wed Feb 12 13:57:14 2025 +0300

    Add missing projects to pabcnetc.sln (#3247)

commit 41dfb6f187
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Fri Feb 7 21:41:01 2025 +0300

    [] - преобразование во все контейнеры

    GraphABCHelper - теперь ABCObjects работает под Линукс

    School исправлен согласно последним веяниям []

commit 79bbbd10ff
Author: samuraiGH <87191377+samuraiGH@users.noreply.github.com>
Date:   Wed Jan 29 20:18:37 2025 +0300

    removing files for support fx4.0 (#3240)

commit 88d5c409eb
Author: samuraiGH <87191377+samuraiGH@users.noreply.github.com>
Date:   Tue Jan 28 20:41:55 2025 +0300

    Рефакторинг PascalABCNET.xshd (#3237)

    * refactoring PascalABCNET.xshd

    * removing extra characters

commit 8fbd7fdfc3
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sun Jan 26 23:42:48 2025 +0300

    3.10.3
    faststrings
    EmptyCollection и преобразование ее в List, Dictionary
    t: (real,real) := (1,2)

commit bba132bd5d
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Jan 22 09:14:44 2025 +0300

    Поправил справку по функции

commit 1bd21857cc
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Jan 8 18:46:51 2025 +0300

    Teacher Control Plugin - возможность задать server.dat

commit 0848a1b796
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Jan 4 22:54:38 2025 +0300

    Исправление автоформатирования []

commit d45b782a7b
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Jan 4 18:45:07 2025 +0300

    Rename PABCSistem in test suite

commit c2347e604b
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Jan 4 14:44:51 2025 +0300

    Примеры - устранил неточности

    LightPT - имя сервера вынес в публичную секцию

commit b68b8da970
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Dec 17 15:52:18 2024 +0300

    Примеры Coords1.pas Coords2.pas.pas

commit 8a9788e6f9
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Dec 17 15:06:57 2024 +0300

    Перенес проверку set array на уровень парсера

    Немного поправил Intellisense по наведению для NewSet

    По точке там что то другое работает

commit 874ddebad3
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Dec 14 21:00:38 2024 +0300

    Поправил грамматику []

    Теперь нельзя в режиме ## использовать атрибуты

    Зато можно [1,2,3].Print

commit 080fb487e1
Merge: a53dcd9ed a484b0e82
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Dec 14 15:25:24 2024 +0300

    Merge branch 'master' of https://github.com/pascalabcnet/pascalabcnet

commit a53dcd9ed2
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Dec 14 15:25:16 2024 +0300

    SF Prm Cmb для строк

commit a484b0e82d
Author: Sun Serega <sunserega2@gmail.com>
Date:   Thu Dec 12 13:49:17 2024 +0200

    fix (#3231)

commit 6ef11f249c
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Dec 10 11:05:45 2024 +0300

    3.10.2

commit db9679d89f
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Dec 10 10:59:20 2024 +0300

    Закончил превращение синтаксиса [] по умолчанию в массивы

commit 45fdde24b4
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Sun Dec 8 18:08:00 2024 +0100

    #3229

commit 494b47624d
Merge: 5875b9929 7906d73da
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Sun Dec 8 10:42:07 2024 +0100

    Merge branch 'master' of https://github.com/pascalabcnet/pascalabcnet

commit 5875b99296
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Sun Dec 8 10:41:53 2024 +0100

    platformtarget native - .NET 9.0

commit 7906d73da3
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Dec 3 14:25:37 2024 +0300

    Небольшие изменения в реализации операций с множествами

commit 087591c7b6
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Nov 27 11:37:07 2024 +0300

    3.10.1

    Coords - доработки

    Distance, Middle, DrawText с фоном и рамкой. Глобальные переменные настройки

commit d268d4f83b
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Thu Nov 21 22:24:07 2024 +0300

    NSToBytes переделал с исключением

commit 2bacdc8c28
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Nov 20 13:20:33 2024 +0300

    Комментарии к NewSet

commit e917ac8eca
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Nov 20 12:42:15 2024 +0300

    TypeName для set

commit 206289c6a7
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Nov 19 20:23:03 2024 +0300

    Везде заменил _hs на hs в NewSet

    Убрал вызовы методов расширений NewSet в PABCSystem.pas

    Убрал var в operator +

commit d8262078f6
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Nov 19 13:56:47 2024 +0300

    Исправление мелких ошибок NewSet

    Все тесты проходят.

    Проблема, которая остаётся - в режиме ускорения такие программы падают:

    begin
      var s: set of byte;
      Print(s = [1]);
    end.

    Причина - из dll не вызывается конструктор записи без параметров, хотя он определён. В C# вообще у записей не может быть конструктора по умолчанию - наверное потому. Но для NewSet надо бы сделать исключение

commit f8819665ba
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Nov 16 10:56:11 2024 +0300

    NS2

commit 591d9ebe60
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Wed Nov 13 21:34:10 2024 +0100

    fix

commit c6505634f4
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Wed Nov 13 21:12:33 2024 +0100

    fix

commit a6564df23c
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Wed Nov 13 20:52:29 2024 +0100

    fix in new sets

commit 03be5bd931
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Wed Nov 13 22:13:41 2024 +0300

    Переставил operator:= в NewSet

commit 96c68f1666
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Tue Nov 12 21:38:07 2024 +0100

    #3223

commit 82776f3c77
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Nov 9 12:18:19 2024 +0300

    NewSet - много мелких исправлений.

    Все тесты проходят кроме Tests 5 - видимо с pabcrtl.dll

* Update comments in PascalABCLanguageInformation
This commit is contained in:
AlexanderZemlyak 2025-04-10 13:13:17 +03:00 committed by GitHub
parent cc7d4472c6
commit 69149f8c44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 1339 additions and 1035 deletions

View file

@ -61,11 +61,7 @@ namespace CodeCompletion
pabcNamespaces.Clear();
}
private static string get_doctagsParserExtension(string ext)
{
return ext + "dt";
}
// нужно переделать на использование ILanguage EVA
public static IParser CurrentParser
{
get
@ -376,18 +372,18 @@ namespace CodeCompletion
return false;
}
public string[] GetKeywords()
public List<string> GetKeywords()
{
if (CodeCompletionController.CurrentParser != null)
return CodeCompletionController.CurrentParser.LanguageInformation.Keywords;
return new string[0];
return CodeCompletionController.CurrentParser.LanguageInformation.KeywordsStorage.Keywords;
return new List<string>();
}
public string[] GetTypeKeywords()
public List<string> GetTypeKeywords()
{
if (CodeCompletionController.CurrentParser != null)
return CodeCompletionController.CurrentParser.LanguageInformation.TypeKeywords;
return new string[0];
return CodeCompletionController.CurrentParser.LanguageInformation.KeywordsStorage.TypeKeywords;
return new List<string>();
}
const string LibSourceDirectoryIdent = "%LIBSOURCEDIRECTORY%";

View file

@ -39,6 +39,8 @@ namespace CodeCompletion
//TreeConverterSymbolTable tcst;
public CodeCompletionController controller;
public bool is_compiled = false;
// TODO: Требуется адаптировать к многоязычности EVA
public static SymInfo[] standard_units;
private Hashtable cur_used_assemblies;
public CompilationUnit unit;

View file

@ -17,14 +17,16 @@ namespace Languages.Facade
/// <summary>
/// Все параметры должны быть не null (и не пустым массивом), кроме IDocParser в случае, если он не требуется
/// </summary>
public BaseLanguage(string name, string version, string copyright, IParser parser, IDocParser docParser,
public BaseLanguage(string name, string version, string copyright, ILanguageInformation languageInformation, IParser parser, IDocParser docParser,
List<ISyntaxTreeConverter> syntaxTreeConverters, syntax_tree_visitor syntaxTreeToSemanticTreeConverter,
string[] filesExtensions, bool caseSensitive, string[] systemUnitNames)
{
this.Name = name;
this.Version = version;
this.Copyright = copyright;
this.LanguageInformation = languageInformation;
this.Parser = parser;
this.Parser.LanguageInformation = languageInformation;
this.DocParser = docParser;
this.SyntaxTreeConverters = syntaxTreeConverters;
this.SyntaxTreeToSemanticTreeConverter = syntaxTreeToSemanticTreeConverter;
@ -39,6 +41,8 @@ namespace Languages.Facade
public virtual string Copyright { get; protected set; }
public virtual ILanguageInformation LanguageInformation { get; }
public virtual IParser Parser { get; protected set; }
public virtual IDocParser DocParser { get; protected set; }

View file

@ -28,6 +28,8 @@ namespace Languages.Facade
/// </summary>
string Copyright { get; }
ILanguageInformation LanguageInformation { get; }
/// <summary>
/// Основной парсер языка
/// </summary>

View file

@ -17,20 +17,7 @@ namespace PascalABCCompiler.Parsers
public Func<bool> CheckIfParsingUnit { get; set; }
public Dictionary<string, ParserTools.Directives.DirectiveInfo> ValidDirectives { get; protected set; }
private ILanguageInformation languageInformation;
public virtual ILanguageInformation LanguageInformation
{
get
{
if (languageInformation == null)
languageInformation = new DefaultLanguageInformation(this);
return languageInformation;
}
}
public BaseKeywords Keywords { get; protected set; }
public ILanguageInformation LanguageInformation { get; set; }
/// <summary>
/// Возвращеает синтаксическое дерево модуля

View file

@ -129,14 +129,17 @@ namespace PascalABCCompiler.Parsers
//char GetParameterDelimiter();
string GetCompiledTypeRepresentation(Type t, System.Reflection.MemberInfo mi, ref int line, ref int col);
bool IsKeyword(string value);
string[] Keywords
{
get;
}
string[] TypeKeywords
BaseKeywords KeywordsStorage
{
get;
}
/// <summary>
/// Данные о всех поддерживаемых директивах компилятора
/// </summary>
Dictionary<string, ParserTools.Directives.DirectiveInfo> ValidDirectives { get; }
string SystemUnitName
{
get;

View file

@ -1,4 +1,4 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// 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 System.Collections.Generic;
using PascalABCCompiler.SyntaxTree;
@ -20,24 +20,11 @@ namespace PascalABCCompiler.Parsers
}
/// <summary>
/// Callback äëÿ ïðîâåðêè, ïàðñèì ëè ìû ñåé÷àñ ìîäóëü èëè íåò (äëÿ ÿçûêîâ áåç êëþ÷åâûõ ñëîâ ó ìîäóëÿ)
/// Callback для проверки, парсим ли мы сейчас модуль или нет (для языков без ключевых слов у модуля)
/// </summary>
Func<bool> CheckIfParsingUnit { get; set; }
/// <summary>
/// Äàííûå î âñåõ ïîääåðæèâàåìûõ äèðåêòèâàõ êîìïèëÿòîðà
/// </summary>
Dictionary<string, ParserTools.Directives.DirectiveInfo> ValidDirectives { get; }
ILanguageInformation LanguageInformation
{
get;
}
/// <summary>
/// Êëàññ, îòâå÷àùèé çà õðàíåíèå è îáðàáîòêó êëþ÷åâûõ ñëîâ ÿçûêà
/// </summary>
BaseKeywords Keywords { get; }
ILanguageInformation LanguageInformation { get; set; }
compilation_unit GetCompilationUnit(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings, ParseMode parseMode, List<string> DefinesList = null);
@ -50,7 +37,6 @@ namespace PascalABCCompiler.Parsers
expression GetTypeAsExpression(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings);
void Reset();
}

View file

@ -12,7 +12,13 @@ namespace PascalABCCompiler.Parsers
/// <summary>
/// Соотвествие ключевых слов токенам
/// </summary>
protected abstract Dictionary<string, int> KeywordsToTokens { get; set; }
public Dictionary<string, int> KeywordsToTokens { get; set; }
public Dictionary<string, KeywordKind> KeywordKinds { get; set; }
public List<string> Keywords { get; set; } = new List<string>();
public List<string> TypeKeywords { get; set; } = new List<string>();
/// <summary>
/// Словарь соответствий ключевых слов их эквивалентам (задается пользователем в специальном файле)
@ -43,7 +49,7 @@ namespace PascalABCCompiler.Parsers
}
/// <summary>
/// Возвращает само эквивалент ключевого слова, либо его само, если эквивалента нет
/// Возвращает эквивалент ключевого слова, либо его самого, если эквивалента нет
/// </summary>
public string ConvertKeyword(string keyword)
{
@ -53,9 +59,13 @@ namespace PascalABCCompiler.Parsers
return keymap[keyword];
}
public BaseKeywords()
public BaseKeywords(bool caseSensitive)
{
ReloadKeyMap();
KeywordsToTokens = new Dictionary<string, int>(caseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase);
KeywordKinds = new Dictionary<string, KeywordKind>(caseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase);
}
/// <summary>
@ -73,5 +83,21 @@ namespace PascalABCCompiler.Parsers
else
return GetIdToken();
}
public void CreateNewKeyword(string name, Enum token, KeywordKind kind = KeywordKind.None, bool isTypeKeyword = false)
{
name = ConvertKeyword(name);
if (kind != KeywordKind.None)
KeywordKinds[name] = kind;
Keywords.Add(name);
KeywordsToTokens[name] = (int)(object)token;
if (isTypeKeyword)
TypeKeywords.Add(name);
// return new Keyword(name, token, kind, isTypeKeyword);
}
}
}

View file

@ -55,33 +55,23 @@ namespace PascalABCCompiler.Parsers
CommonExpressionKeyword
}
/*public class Keyword
/*public struct Keyword
{
string _name;
KeywordKind _kind = KeywordKind.None;
public string Name
public string Name { get; set; }
public KeywordKind Kind { get; set; }
public bool IsTypeKeyword { get; set; }
public System.Enum Token { get; set; }
public Keyword(string name, System.Enum token, KeywordKind kind = KeywordKind.None, bool isTypeKeyword = false)
{
get
{
return _name;
}
}
KeywordKind Kind
{
get
{
return _kind;
}
}
public Keyword(string name, KeywordKind kind)
{
_name = name;
_kind = kind;
}
public Keyword(string name)
{
_name = name;
Name = name;
Token = token;
Kind = kind;
IsTypeKeyword = isTypeKeyword;
}
public override string ToString()
{
return Name;

View file

@ -1,126 +1,120 @@
// 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 System;
using System.Collections.Generic;
using System.Linq;
using PascalABCCompiler.Parsers;
namespace Languages.Pascal.Frontend.Core
{
public class PascalABCKeywords : PascalABCCompiler.Parsers.BaseKeywords
public class PascalABCKeywords : BaseKeywords
{
protected override string FileName => "keywordsmap.pabc";
protected override Dictionary<string, int> KeywordsToTokens { get; set; }
public PascalABCKeywords() : base()
public PascalABCKeywords() : base(false)
{
KeywordsToTokens = new Dictionary<string, int>
{
["or"] = (int)Tokens.tkOr,
["xor"] = (int)Tokens.tkXor,
["and"] = (int)Tokens.tkAnd,
["div"] = (int)Tokens.tkDiv,
["mod"] = (int)Tokens.tkMod,
["shl"] = (int)Tokens.tkShl,
["shr"] = (int)Tokens.tkShr,
["not"] = (int)Tokens.tkNot,
["as"] = (int)Tokens.tkAs,
["in"] = (int)Tokens.tkIn,
["is"] = (int)Tokens.tkIs,
["implicit"] = (int)Tokens.tkImplicit,
["explicit"] = (int)Tokens.tkExplicit,
["sizeof"] = (int)Tokens.tkSizeOf,
["typeof"] = (int)Tokens.tkTypeOf,
["where"] = (int)Tokens.tkWhere,
["array"] = (int)Tokens.tkArray,
["begin"] = (int)Tokens.tkBegin,
["case"] = (int)Tokens.tkCase,
["class"] = (int)Tokens.tkClass,
["const"] = (int)Tokens.tkConst,
["constructor"] = (int)Tokens.tkConstructor,
["default"] = (int)Tokens.tkDefault,
["destructor"] = (int)Tokens.tkDestructor,
["downto"] = (int)Tokens.tkDownto,
["do"] = (int)Tokens.tkDo,
["else"] = (int)Tokens.tkElse,
["end"] = (int)Tokens.tkEnd,
["event"] = (int)Tokens.tkEvent,
["except"] = (int)Tokens.tkExcept,
["exports"] = (int)Tokens.tkExports,
["file"] = (int)Tokens.tkFile,
["finalization"] = (int)Tokens.tkFinalization,
["finally"] = (int)Tokens.tkFinally,
["for"] = (int)Tokens.tkFor,
["foreach"] = (int)Tokens.tkForeach,
["function"] = (int)Tokens.tkFunction,
["goto"] = (int)Tokens.tkGoto,
["if"] = (int)Tokens.tkIf,
["implementation"] = (int)Tokens.tkImplementation,
["inherited"] = (int)Tokens.tkInherited,
["initialization"] = (int)Tokens.tkInitialization,
["interface"] = (int)Tokens.tkInterface,
["label"] = (int)Tokens.tkLabel,
["lock"] = (int)Tokens.tkLock,
["loop"] = (int)Tokens.tkLoop,
["nil"] = (int)Tokens.tkNil,
["procedure"] = (int)Tokens.tkProcedure,
["of"] = (int)Tokens.tkOf,
["operator"] = (int)Tokens.tkOperator,
["property"] = (int)Tokens.tkProperty,
["raise"] = (int)Tokens.tkRaise,
["record"] = (int)Tokens.tkRecord,
["repeat"] = (int)Tokens.tkRepeat,
["set"] = (int)Tokens.tkSet,
["try"] = (int)Tokens.tkTry,
["type"] = (int)Tokens.tkType,
["then"] = (int)Tokens.tkThen,
["to"] = (int)Tokens.tkTo,
["until"] = (int)Tokens.tkUntil,
["uses"] = (int)Tokens.tkUses,
["var"] = (int)Tokens.tkVar,
["while"] = (int)Tokens.tkWhile,
["with"] = (int)Tokens.tkWith,
["program"] = (int)Tokens.tkProgram,
["template"] = (int)Tokens.tkTemplate,
["resourcestring"] = (int)Tokens.tkResourceString,
["threadvar"] = (int)Tokens.tkThreadvar,
["sealed"] = (int)Tokens.tkSealed,
["partial"] = (int)Tokens.tkPartial,
["params"] = (int)Tokens.tkParams,
["unit"] = (int)Tokens.tkUnit,
["library"] = (int)Tokens.tkLibrary,
["external"] = (int)Tokens.tkExternal,
["name"] = (int)Tokens.tkName,
["private"] = (int)Tokens.tkPrivate,
["protected"] = (int)Tokens.tkProtected,
["public"] = (int)Tokens.tkPublic,
["internal"] = (int)Tokens.tkInternal,
["read"] = (int)Tokens.tkRead,
["write"] = (int)Tokens.tkWrite,
["on"] = (int)Tokens.tkOn,
["forward"] = (int)Tokens.tkForward,
["abstract"] = (int)Tokens.tkAbstract,
["overload"] = (int)Tokens.tkOverload,
["reintroduce"] = (int)Tokens.tkReintroduce,
["override"] = (int)Tokens.tkOverride,
["virtual"] = (int)Tokens.tkVirtual,
["extensionmethod"] = (int)Tokens.tkExtensionMethod,
["new"] = (int)Tokens.tkNew,
["auto"] = (int)Tokens.tkAuto,
["sequence"] = (int)Tokens.tkSequence,
["yield"] = (int)Tokens.tkYield,
["match"] = (int)Tokens.tkMatch,
["when"] = (int)Tokens.tkWhen,
["namespace"] = (int)Tokens.tkNamespace,
["static"] = (int)Tokens.tkStatic,
["step"] = (int)Tokens.tkStep,
["index"] = (int)Tokens.tkIndex,
["async"] = (int)Tokens.tkAsync,
["await"] = (int)Tokens.tkAwait
}
.ToDictionary(kv => ConvertKeyword(kv.Key), kv => kv.Value, StringComparer.CurrentCultureIgnoreCase);
#region Keywords Initialization
CreateNewKeyword("or", Tokens.tkOr);
CreateNewKeyword("xor", Tokens.tkXor);
CreateNewKeyword("and", Tokens.tkAnd);
CreateNewKeyword("div", Tokens.tkDiv);
CreateNewKeyword("mod", Tokens.tkMod);
CreateNewKeyword("shl", Tokens.tkShl);
CreateNewKeyword("shr", Tokens.tkShr);
CreateNewKeyword("not", Tokens.tkNot);
CreateNewKeyword("as", Tokens.tkAs);
CreateNewKeyword("in", Tokens.tkIn);
CreateNewKeyword("is", Tokens.tkIs);
CreateNewKeyword("implicit", Tokens.tkImplicit);
CreateNewKeyword("explicit", Tokens.tkExplicit);
CreateNewKeyword("sizeof", Tokens.tkSizeOf);
CreateNewKeyword("typeof", Tokens.tkTypeOf);
CreateNewKeyword("where", Tokens.tkWhere);
CreateNewKeyword("array", Tokens.tkArray, isTypeKeyword: true);
CreateNewKeyword("begin", Tokens.tkBegin);
CreateNewKeyword("case", Tokens.tkCase);
CreateNewKeyword("class", Tokens.tkClass, isTypeKeyword: true);
CreateNewKeyword("const", Tokens.tkConst, KeywordKind.Const);
CreateNewKeyword("constructor", Tokens.tkConstructor, KeywordKind.Constructor);
CreateNewKeyword("default", Tokens.tkDefault);
CreateNewKeyword("destructor", Tokens.tkDestructor, KeywordKind.Destructor);
CreateNewKeyword("downto", Tokens.tkDownto);
CreateNewKeyword("do", Tokens.tkDo);
CreateNewKeyword("else", Tokens.tkElse);
CreateNewKeyword("end", Tokens.tkEnd);
CreateNewKeyword("event", Tokens.tkEvent);
CreateNewKeyword("except", Tokens.tkExcept);
CreateNewKeyword("exports", Tokens.tkExports);
CreateNewKeyword("file", Tokens.tkFile, isTypeKeyword : true);
CreateNewKeyword("finalization", Tokens.tkFinalization);
CreateNewKeyword("finally", Tokens.tkFinally);
CreateNewKeyword("for", Tokens.tkFor);
CreateNewKeyword("foreach", Tokens.tkForeach);
CreateNewKeyword("function", Tokens.tkFunction, KeywordKind.Function, true);
CreateNewKeyword("goto", Tokens.tkGoto);
CreateNewKeyword("if", Tokens.tkIf);
CreateNewKeyword("implementation", Tokens.tkImplementation);
CreateNewKeyword("inherited", Tokens.tkInherited, KeywordKind.Inherited);
CreateNewKeyword("initialization", Tokens.tkInitialization);
CreateNewKeyword("interface", Tokens.tkInterface);
CreateNewKeyword("label", Tokens.tkLabel);
CreateNewKeyword("lock", Tokens.tkLock);
CreateNewKeyword("loop", Tokens.tkLoop);
CreateNewKeyword("nil", Tokens.tkNil);
CreateNewKeyword("procedure", Tokens.tkProcedure, KeywordKind.Function, true);
CreateNewKeyword("of", Tokens.tkOf, KeywordKind.Of);
CreateNewKeyword("operator", Tokens.tkOperator);
CreateNewKeyword("property", Tokens.tkProperty);
CreateNewKeyword("raise", Tokens.tkRaise, KeywordKind.Raise);
CreateNewKeyword("record", Tokens.tkRecord, isTypeKeyword: true);
CreateNewKeyword("repeat", Tokens.tkRepeat);
CreateNewKeyword("set", Tokens.tkSet, isTypeKeyword : true);
CreateNewKeyword("try", Tokens.tkTry);
CreateNewKeyword("type", Tokens.tkType, KeywordKind.Type);
CreateNewKeyword("then", Tokens.tkThen);
CreateNewKeyword("to", Tokens.tkTo);
CreateNewKeyword("until", Tokens.tkUntil);
CreateNewKeyword("uses", Tokens.tkUses, KeywordKind.Uses);
CreateNewKeyword("var", Tokens.tkVar, KeywordKind.Var);
CreateNewKeyword("while", Tokens.tkWhile);
CreateNewKeyword("with", Tokens.tkWith);
CreateNewKeyword("program", Tokens.tkProgram, KeywordKind.Program);
CreateNewKeyword("template", Tokens.tkTemplate);
CreateNewKeyword("resourcestring", Tokens.tkResourceString);
CreateNewKeyword("threadvar", Tokens.tkThreadvar);
CreateNewKeyword("sealed", Tokens.tkSealed);
CreateNewKeyword("partial", Tokens.tkPartial);
CreateNewKeyword("params", Tokens.tkParams);
CreateNewKeyword("unit", Tokens.tkUnit, KeywordKind.Unit);
CreateNewKeyword("library", Tokens.tkLibrary);
CreateNewKeyword("external", Tokens.tkExternal);
CreateNewKeyword("name", Tokens.tkName);
CreateNewKeyword("private", Tokens.tkPrivate);
CreateNewKeyword("protected", Tokens.tkProtected);
CreateNewKeyword("public", Tokens.tkPublic);
CreateNewKeyword("internal", Tokens.tkInternal);
CreateNewKeyword("read", Tokens.tkRead);
CreateNewKeyword("write", Tokens.tkWrite);
CreateNewKeyword("on", Tokens.tkOn);
CreateNewKeyword("forward", Tokens.tkForward);
CreateNewKeyword("abstract", Tokens.tkAbstract);
CreateNewKeyword("overload", Tokens.tkOverload);
CreateNewKeyword("reintroduce", Tokens.tkReintroduce);
CreateNewKeyword("override", Tokens.tkOverride);
CreateNewKeyword("virtual", Tokens.tkVirtual);
CreateNewKeyword("extensionmethod", Tokens.tkExtensionMethod);
CreateNewKeyword("new", Tokens.tkNew, KeywordKind.New);
CreateNewKeyword("auto", Tokens.tkAuto);
CreateNewKeyword("sequence", Tokens.tkSequence);
CreateNewKeyword("yield", Tokens.tkYield);
CreateNewKeyword("match", Tokens.tkMatch);
CreateNewKeyword("when", Tokens.tkWhen);
CreateNewKeyword("namespace", Tokens.tkNamespace);
CreateNewKeyword("static", Tokens.tkStatic);
CreateNewKeyword("step", Tokens.tkStep);
CreateNewKeyword("index", Tokens.tkIndex);
CreateNewKeyword("async", Tokens.tkAsync);
CreateNewKeyword("await", Tokens.tkAwait);
#endregion
}
protected override int GetIdToken() => (int)Tokens.tkIdentifier;

View file

@ -5,10 +5,7 @@ using System.IO;
using System.Collections.Generic;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.Parsers;
using PascalABCCompiler;
using Languages.Pascal.Frontend.Core;
using PascalABCCompiler.ParserTools.Directives;
using static PascalABCCompiler.ParserTools.Directives.DirectiveHelper;
namespace Languages.Pascal.Frontend.Wrapping
{
@ -75,66 +72,12 @@ namespace Languages.Pascal.Frontend.Wrapping
public class PascalABCNewLanguageParser : BaseParser
{
public PascalABCNewLanguageParser()
{
InitializeValidDirectives();
Keywords = new PascalABCKeywords();
}
public override void Reset()
{
CompilerDirectives = new List<compiler_directive>();
Errors.Clear();
}
/// <summary>
/// Здесь записываются все директивы, поддерживаемые языком, а также правила для проверки их параметров (ограничения, накладываемые со стороны языка)
/// </summary>
private void InitializeValidDirectives()
{
#region VALID DIRECTIVES
ValidDirectives = new Dictionary<string, DirectiveInfo>(StringComparer.CurrentCultureIgnoreCase)
{
[StringConstants.compiler_directive_apptype] = new DirectiveInfo(SingleAnyOfCheck("console", "windows", "dll", "pcu")),
[StringConstants.compiler_directive_reference] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_include_namespace] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_savepcu] = new DirectiveInfo(SingleAnyOfCheck("true", "false")),
[StringConstants.compiler_directive_zerobasedstrings] = new DirectiveInfo(SingleAnyOfCheck("on", "off"), paramsNums: new int[2] { 0, 1 }),
[StringConstants.compiler_directive_zerobasedstrings_ON] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_zerobasedstrings_OFF] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_nullbasedstrings_ON] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_nullbasedstrings_OFF] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_initstring_as_empty_ON] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_initstring_as_empty_OFF] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_resource] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_platformtarget] = new DirectiveInfo(SingleAnyOfCheck("x86", "x64", "anycpu", "dotnet5win", "dotnet5linux", "dotnet5macos", "native")),
[StringConstants.compiler_directive_faststrings] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_gendoc] = new DirectiveInfo(SingleAnyOfCheck("true", "false")),
[StringConstants.compiler_directive_region] = new DirectiveInfo(checkParamsNumNeeded: false),
[StringConstants.compiler_directive_endregion] = new DirectiveInfo(checkParamsNumNeeded: false),
[StringConstants.compiler_directive_ifdef] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_endif] = new DirectiveInfo(SingleIsValidIdCheck(), paramsNums: new int[2] { 0, 1 }),
[StringConstants.compiler_directive_ifndef] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_else] = new DirectiveInfo(SingleIsValidIdCheck(), paramsNums: new int[2] { 0, 1 }),
[StringConstants.compiler_directive_undef] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_define] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_include] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_targetframework] = new DirectiveInfo(),
[StringConstants.compiler_directive_hidden_idents] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_disable_standard_units] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_version_string] = new DirectiveInfo(IsValidVersionCheck()),
[StringConstants.compiler_directive_product_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_company_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_trademark_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_main_resource_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_title_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_description_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_omp] = new DirectiveInfo(SingleAnyOfCheck("critical", "parallel"), checkParamsNumNeeded: false)
};
#endregion
}
protected override void PreBuildTree(string FileName)
{
CompilerDirectives = new List<compiler_directive>();
@ -151,11 +94,11 @@ namespace Languages.Pascal.Frontend.Wrapping
#endif
#endif
PascalParserTools parserTools = new PascalParserTools(Errors, Warnings, ValidDirectives,
PascalParserTools parserTools = new PascalParserTools(Errors, Warnings, LanguageInformation.ValidDirectives,
buildTreeForFormatter, false,
Path.GetFullPath(fileName), CompilerDirectives); // контекст сканера и парсера
Scanner scanner = new Scanner(Text, parserTools, Keywords, definesList);
Scanner scanner = new Scanner(Text, parserTools, LanguageInformation.KeywordsStorage, definesList);
GPPGParser parser = new GPPGParser(scanner, parserTools);
@ -192,11 +135,12 @@ namespace Languages.Pascal.Frontend.Wrapping
syntax_tree_node root = Parse(Text, FileName);
if (root == null && origText != null && origText.Contains("<"))
// убрали эту вторую попытку пока, т.к. Intellisense не должен выдавать подсказку в случае, когда компилятор выдает ошибку в такой ситуации EVA 10.10.2024
/*if (root == null && origText != null && origText.Contains("<"))
{
Errors.Clear();
root = Parse(String.Concat("<<expression>>", Environment.NewLine, origText.Replace("<", "&<")), FileName);
}
}*/
return root as expression;
}

View file

@ -18,6 +18,7 @@ namespace Languages.Pascal
version: "1.2",
copyright: "Copyright © 2005-2025 by Ivan Bondarev, Stanislav Mikhalkovich",
languageInformation: new Frontend.Data.PascalABCLanguageInformation(),
parser: new Frontend.Wrapping.PascalABCNewLanguageParser(),
docParser: new Frontend.Documentation.PascalDocTagsLanguageParser(),

View file

@ -3,142 +3,89 @@
using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using PascalABCCompiler.SyntaxTree;
using System.Reflection;
namespace PascalABCCompiler.Parsers
using PascalABCCompiler.Parsers;
using PascalABCCompiler;
using PascalABCCompiler.ParserTools.Directives;
using static PascalABCCompiler.ParserTools.Directives.DirectiveHelper;
namespace Languages.Pascal.Frontend.Data
{
public class DefaultLanguageInformation : ILanguageInformation
public class PascalABCLanguageInformation : ILanguageInformation
{
protected IParser parser;
protected string[] type_keywords_array;
protected string[] keywords_array;
protected Dictionary<string, string> keywords = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
protected Hashtable ignored_keywords = new Hashtable(StringComparer.CurrentCultureIgnoreCase);
protected Hashtable keyword_kinds = new Hashtable(StringComparer.CurrentCultureIgnoreCase);
public DefaultLanguageInformation()
protected IParser Parser
{
get
{
// Поле парсера желательно убрать отсюда EVA
return Facade.LanguageProvider.Instance.SelectLanguageByName(StringConstants.pascalLanguageName).Parser;
}
}
public DefaultLanguageInformation(IParser p)
public BaseKeywords KeywordsStorage { get; } = new Core.PascalABCKeywords();
public Dictionary<string, DirectiveInfo> ValidDirectives { get; private set; }
public PascalABCLanguageInformation()
{
this.parser = p;
InitKeywords();
InitializeValidDirectives();
}
protected virtual void InitKeywords()
/// <summary>
/// Здесь записываются все директивы, поддерживаемые языком, а также правила для проверки их параметров (ограничения, накладываемые со стороны языка)
/// </summary>
private void InitializeValidDirectives()
{
List<string> keys = new List<string>();
List<string> type_keys = new List<string>();
keywords.Add("and", "and"); keys.Add("and");
keywords.Add("or", "or"); keys.Add("or");
keywords.Add("xor", "xor"); keys.Add("xor");
keywords.Add("begin", "begin"); keys.Add("begin");
keywords.Add("end", "end"); keys.Add("end");
keywords.Add("for", "for"); keys.Add("for");
keywords.Add("while", "while"); keys.Add("while");
keywords.Add("repeat", "repeat"); keys.Add("repeat");
keywords.Add("until", "until"); keys.Add("until");
keywords.Add("do", "do"); keys.Add("do");
keywords.Add("to", "to"); keys.Add("to");
keywords.Add("downto", "downto"); keys.Add("downto");
keywords.Add("class", "class"); keys.Add("class"); type_keys.Add("class");
keywords.Add("record", "record"); keys.Add("record"); type_keys.Add("record");
keywords.Add("set", "set"); keys.Add("set"); type_keys.Add("set");
keywords.Add("file", "file"); keys.Add("file"); type_keys.Add("file");
keywords.Add("type", "type"); keys.Add("type"); keyword_kinds.Add("type", KeywordKind.Type);
keywords.Add("array", "array"); keys.Add("array"); type_keys.Add("array");
keywords.Add("of", "of"); keys.Add("of"); keyword_kinds.Add("of", KeywordKind.Of);
keywords.Add("private", "private"); keys.Add("private");
keywords.Add("protected", "protected"); keys.Add("protected");
keywords.Add("public", "public"); keys.Add("public");
keywords.Add("inherited", "inherited"); keys.Add("inherited"); keyword_kinds.Add("inherited", KeywordKind.Inherited);
keywords.Add("foreach", "foreach"); keys.Add("foreach");
keywords.Add("try", "try"); keys.Add("try");
keywords.Add("except", "except"); keys.Add("except");
keywords.Add("finally", "finally"); keys.Add("finally");
keywords.Add("uses", "uses"); keys.Add("uses"); keyword_kinds.Add("uses", KeywordKind.Uses);
keywords.Add("unit", "unit"); keys.Add("unit"); keyword_kinds.Add("unit", KeywordKind.Unit);
keywords.Add("procedure", "procedure"); keys.Add("procedure"); keyword_kinds.Add("procedure", KeywordKind.Function); type_keys.Add("procedure");
keywords.Add("function", "function"); keys.Add("function"); keyword_kinds.Add("function", KeywordKind.Function); type_keys.Add("function");
keywords.Add("constructor", "constructor"); keys.Add("constructor"); keyword_kinds.Add("constructor", KeywordKind.Constructor);
keywords.Add("destructor", "destructor"); keys.Add("destructor"); keyword_kinds.Add("destructor", KeywordKind.Destructor);
keywords.Add("interface", "interface"); keys.Add("interface");
keywords.Add("implementation", "implementation"); keys.Add("implementation");
keywords.Add("initialization", "initialization"); keys.Add("initialization");
keywords.Add("finalization", "finalization"); keys.Add("finalization");
keywords.Add("with", "with"); keys.Add("with");
keywords.Add("abstract","abstract"); keys.Add("abstract");
keywords.Add("virtual", "virtual"); keys.Add("virtual");
keywords.Add("override", "override"); keys.Add("override");
keywords.Add("reintroduce", "reintroduce"); keys.Add("reintroduce");
keywords.Add("sealed", "sealed"); keys.Add("sealed");
keywords.Add("case", "case"); keys.Add("case");
keywords.Add("var", "var"); keys.Add("var"); keyword_kinds.Add("var", KeywordKind.Var);
keywords.Add("const", "const"); keys.Add("const"); keyword_kinds.Add("const", KeywordKind.Const);
keywords.Add("if", "if"); keys.Add("if");
keywords.Add("then", "then"); keys.Add("then");
keywords.Add("else", "else"); keys.Add("else");
keywords.Add("in", "in"); keys.Add("in");
keywords.Add("operator", "operator"); keys.Add("operator");
keywords.Add("raise", "raise"); keys.Add("raise"); keyword_kinds.Add("raise", KeywordKind.Raise);
keywords.Add("program", "program"); keys.Add("program"); keyword_kinds.Add("program", KeywordKind.Program);
keywords.Add("new", "new"); keys.Add("new"); keyword_kinds.Add("new", KeywordKind.New);
keywords.Add("nil", "nil"); keys.Add("nil");
keywords.Add("loop", "loop"); keys.Add("loop");
keywords.Add("yield", "yield"); keys.Add("yield");
keywords.Add("sequence", "sequence"); keys.Add("sequence");
keywords.Add("extensionmethod", "extensionmethod"); keys.Add("extensionmethod");
keywords.Add("params", "params"); keys.Add("params");
keywords.Add("implicit", "implicit"); keys.Add("implicit");
keywords.Add("explicit", "explicit"); keys.Add("explicit");
keywords.Add("forward", "forward"); keys.Add("forward");
keywords.Add("break", "break"); keys.Add("break");
keywords.Add("continue", "continue"); keys.Add("continue");
keywords.Add("default", "default"); keys.Add("default");
keywords.Add("label", "label"); keys.Add("label");
keywords.Add("property", "property"); keys.Add("property");
keywords.Add("auto", "auto"); keys.Add("auto");
keywords.Add("external", "external"); keys.Add("external");
keywords.Add("lock", "lock"); keys.Add("lock");
keywords.Add("where", "where"); keys.Add("where");
keywords.Add("library", "library"); keys.Add("library");
keywords.Add("div", "div"); keys.Add("div");
keywords.Add("mod", "mod"); keys.Add("mod");
keywords.Add("shl", "shl"); keys.Add("shl");
keywords.Add("shr", "shr"); keys.Add("shr");
keywords.Add("not", "not"); keys.Add("not");
keywords.Add("as", "as"); keys.Add("as");
keywords.Add("is", "is"); keys.Add("is");
keywords.Add("on", "on"); keys.Add("on");
keywords.Add("goto", "goto"); keys.Add("goto");
keywords.Add("overload", "overload"); keys.Add("overload");
keywords.Add("internal", "internal"); keys.Add("internal");
//keywords.Add("template", "template"); keys.Add("template");
keywords.Add("partial", "partial"); keys.Add("partial");
keywords.Add("namespace", "namespace"); keys.Add("namespace");
keywords.Add("exit", "exit"); keys.Add("exit");
keywords.Add("event", "event"); keys.Add("event");
keywords.Add("match", "match"); keys.Add("match");
keywords.Add("when", "when"); keys.Add("when");
keywords.Add("static", "static"); keys.Add("static");
//keywords.Add("typeof", "typeof"); //keys.Add("typeof");
//keywords.Add("sizeof", "sizeof"); //keys.Add("sizeof");
keywords_array = new string[keywords.Count + 2];
keywords_array[0] = "typeof";
keywords_array[1] = "sizeof";
keywords.Values.CopyTo(keywords_array, 2);
type_keywords_array = type_keys.ToArray();
#region VALID DIRECTIVES
ValidDirectives = new Dictionary<string, DirectiveInfo>(StringComparer.CurrentCultureIgnoreCase)
{
[StringConstants.compiler_directive_apptype] = new DirectiveInfo(SingleAnyOfCheck("console", "windows", "dll", "pcu")),
[StringConstants.compiler_directive_reference] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_include_namespace] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_savepcu] = new DirectiveInfo(SingleAnyOfCheck("true", "false")),
[StringConstants.compiler_directive_zerobasedstrings] = new DirectiveInfo(SingleAnyOfCheck("on", "off"), paramsNums: new int[2] { 0, 1 }),
[StringConstants.compiler_directive_zerobasedstrings_ON] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_zerobasedstrings_OFF] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_nullbasedstrings_ON] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_nullbasedstrings_OFF] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_initstring_as_empty_ON] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_initstring_as_empty_OFF] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_resource] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_platformtarget] = new DirectiveInfo(SingleAnyOfCheck("x86", "x64", "anycpu", "dotnet5win", "dotnet5linux", "dotnet5macos", "native")),
[StringConstants.compiler_directive_faststrings] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_gendoc] = new DirectiveInfo(SingleAnyOfCheck("true", "false")),
[StringConstants.compiler_directive_region] = new DirectiveInfo(checkParamsNumNeeded: false),
[StringConstants.compiler_directive_endregion] = new DirectiveInfo(checkParamsNumNeeded: false),
[StringConstants.compiler_directive_ifdef] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_endif] = new DirectiveInfo(SingleIsValidIdCheck(), paramsNums: new int[2] { 0, 1 }),
[StringConstants.compiler_directive_ifndef] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_else] = new DirectiveInfo(SingleIsValidIdCheck(), paramsNums: new int[2] { 0, 1 }),
[StringConstants.compiler_directive_undef] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_define] = new DirectiveInfo(SingleIsValidIdCheck()),
[StringConstants.compiler_directive_include] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_targetframework] = new DirectiveInfo(),
[StringConstants.compiler_directive_hidden_idents] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_disable_standard_units] = NoParamsDirectiveInfo(),
[StringConstants.compiler_directive_version_string] = new DirectiveInfo(IsValidVersionCheck()),
[StringConstants.compiler_directive_product_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_company_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_trademark_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_main_resource_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_title_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_description_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
[StringConstants.compiler_directive_omp] = new DirectiveInfo(SingleAnyOfCheck("critical", "parallel"), checkParamsNumNeeded: false)
};
#endregion
}
public bool IsKeyword(string value)
{
return keywords.ContainsKey(value.ToLower());
// typeof и sizeof воспринимаются Intellisense по другому EVA
return !value.Equals("typeof", StringComparison.CurrentCultureIgnoreCase) && !value.Equals("sizeof", StringComparison.CurrentCultureIgnoreCase)
&& KeywordsStorage.KeywordsToTokens.ContainsKey(value);
}
public virtual string BodyStartBracket
@ -161,23 +108,23 @@ namespace PascalABCCompiler.Parsers
{
get
{
return "PABCSystem";
return PascalABCCompiler.StringConstants.pascalSystemUnitName;
}
}
public string[] Keywords
public List<string> Keywords
{
get
{
return keywords_array;
return KeywordsStorage.Keywords;
}
}
public string[] TypeKeywords
public List<string> TypeKeywords
{
get
{
return type_keywords_array;
return KeywordsStorage.TypeKeywords;
}
}
@ -631,9 +578,9 @@ namespace PascalABCCompiler.Parsers
if (!string.IsNullOrEmpty(doc))
{
doc = doc.Trim(' ', '\n', '\t', '\r').Replace(Environment.NewLine, Environment.NewLine + " /// ");
doc = doc.Replace("<returns>", StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<returns>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<params>", "");
doc = doc.Replace("<param>", StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("<param>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("</param>", "");
sb.AppendLine(" /// " + doc);
}
@ -698,7 +645,7 @@ namespace PascalABCCompiler.Parsers
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (fields.Length > 0)
{
sb.AppendLine(" {$region " + StringResources.Get("CODE_COMPLETION_FIELDS") + "}");
sb.AppendLine(" {$region " + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_FIELDS") + "}");
for (int i = 0; i < fields.Length; i++)
{
if (fields[i].DeclaringType == t && !fields[i].IsPrivate && !fields[i].IsAssembly)
@ -707,9 +654,9 @@ namespace PascalABCCompiler.Parsers
if (!string.IsNullOrEmpty(doc))
{
doc = doc.Trim(' ', '\n', '\t', '\r').Replace(Environment.NewLine, Environment.NewLine + " /// ");
doc = doc.Replace("<returns>", StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<returns>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<params>", "");
doc = doc.Replace("<param>", StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("<param>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("</param>", "");
sb.AppendLine(" /// " + doc);
ln++;
@ -731,7 +678,7 @@ namespace PascalABCCompiler.Parsers
EventInfo[] events = t.GetEvents(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (events.Length > 0)
{
sb.AppendLine(" {$region " + StringResources.Get("CODE_COMPLETION_EVENTS") + "}");
sb.AppendLine(" {$region " + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_EVENTS") + "}");
for (int i = 0; i < events.Length; i++)
{
if (events[i].DeclaringType != t)
@ -743,9 +690,9 @@ namespace PascalABCCompiler.Parsers
if (!string.IsNullOrEmpty(doc))
{
doc = doc.Trim(' ', '\n', '\t', '\r').Replace(Environment.NewLine, Environment.NewLine + " /// ");
doc = doc.Replace("<returns>", StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<returns>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<params>", "");
doc = doc.Replace("<param>", StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("<param>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("</param>", "");
sb.AppendLine(" /// " + doc);
}
@ -767,7 +714,7 @@ namespace PascalABCCompiler.Parsers
PropertyInfo[] props = t.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (props.Length > 0)
{
sb.AppendLine(" {$region " + StringResources.Get("CODE_COMPLETION_PROPERTIES") + "}");
sb.AppendLine(" {$region " + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_PROPERTIES") + "}");
for (int i = 0; i < props.Length; i++)
{
if (props[i].DeclaringType != t)
@ -779,9 +726,9 @@ namespace PascalABCCompiler.Parsers
if (!string.IsNullOrEmpty(doc))
{
doc = doc.Trim(' ', '\n', '\t', '\r').Replace(Environment.NewLine, Environment.NewLine + " /// ");
doc = doc.Replace("<returns>", StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<returns>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<params>", "");
doc = doc.Replace("<param>", StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("<param>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("</param>", "");
sb.AppendLine(" /// " + doc);
}
@ -803,7 +750,7 @@ namespace PascalABCCompiler.Parsers
ConstructorInfo[] constrs = t.GetConstructors(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (constrs.Length > 0)
{
sb.AppendLine(" {$region " + StringResources.Get("CODE_COMPLETION_CONSTRUCTORS") + "}");
sb.AppendLine(" {$region " + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_CONSTRUCTORS") + "}");
for (int i = 0; i < constrs.Length; i++)
{
if (constrs[i].DeclaringType == t && !constrs[i].IsPrivate && !constrs[i].IsAssembly)
@ -812,9 +759,9 @@ namespace PascalABCCompiler.Parsers
if (!string.IsNullOrEmpty(doc))
{
doc = doc.Trim(' ', '\n', '\t', '\r').Replace(Environment.NewLine, Environment.NewLine + " /// ");
doc = doc.Replace("<returns>", StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<returns>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<params>", "");
doc = doc.Replace("<param>", StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("<param>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("</param>", "");
sb.AppendLine(" /// " + doc);
}
@ -835,7 +782,7 @@ namespace PascalABCCompiler.Parsers
MethodInfo[] meths = t.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (meths.Length > 0)
{
sb.AppendLine(" {$region " + StringResources.Get("CODE_COMPLETION_METHODS") + "}");
sb.AppendLine(" {$region " + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_METHODS") + "}");
for (int i = 0; i < meths.Length; i++)
{
if (meths[i].DeclaringType == t && !meths[i].IsPrivate && !meths[i].IsAssembly && !meths[i].Name.StartsWith("get_") && !meths[i].Name.StartsWith("set_") && !meths[i].Name.StartsWith("add_") && !meths[i].Name.StartsWith("remove_"))
@ -844,9 +791,9 @@ namespace PascalABCCompiler.Parsers
if (!string.IsNullOrEmpty(doc))
{
doc = doc.Trim(' ', '\n', '\t', '\r').Replace(Environment.NewLine, Environment.NewLine + " /// ");
doc = doc.Replace("<returns>", StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<returns>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_RETURN_VALUE"));
doc = doc.Replace("<params>", "");
doc = doc.Replace("<param>", StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("<param>", PascalABCCompiler.StringResources.Get("CODE_COMPLETION_PARAMETER"));
doc = doc.Replace("</param>", "");
sb.AppendLine(" /// " + doc);
}
@ -1015,7 +962,7 @@ namespace PascalABCCompiler.Parsers
var strrank = rank > 1 ? "[" + new string(',', rank - 1) + "]" : "";
return $"array{strrank}" + " of " + GetShortTypeName(ctn.GetElementType());
}
//if (ctn == Type.GetType("System.Void*")) return StringConstants.pointer_type_name;
//if (ctn == Type.GetType("System.Void*")) return PascalABCCompiler.StringConstants.pointer_type_name;
return ctn.Name;
}
@ -1851,11 +1798,11 @@ namespace PascalABCCompiler.Parsers
{
if (extensionType.IndexOf(' ') != -1)
{
sb.Append("(" + StringResources.Get("CODE_COMPLETION_EXTENSION") + " " + extensionType + ") ");
sb.Append("(" + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_EXTENSION") + " " + extensionType + ") ");
}
else
{
sb.Append("(" + StringResources.Get("CODE_COMPLETION_EXTENSION") + ") ");
sb.Append("(" + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_EXTENSION") + ") ");
extensionType = null;
}
}
@ -2056,12 +2003,12 @@ namespace PascalABCCompiler.Parsers
{
if (extensionType != null && extensionType.IndexOf(' ') != -1)
{
sb.Append("(" + StringResources.Get("CODE_COMPLETION_EXTENSION") + " " + extensionType + ") ");
sb.Append("(" + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_EXTENSION") + " " + extensionType + ") ");
extensionType = null;
}
else
{
sb.Append("(" + StringResources.Get("CODE_COMPLETION_EXTENSION")+ ") ");
sb.Append("(" + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_EXTENSION")+ ") ");
}
}
@ -2167,7 +2114,7 @@ namespace PascalABCCompiler.Parsers
private string prepare_member_name(string s)
{
if (keywords.ContainsKey(s))
if (IsKeyword(s))
return "&" + s;
return s;
}
@ -2351,9 +2298,10 @@ namespace PascalABCCompiler.Parsers
public KeywordKind GetKeywordKind(string name)
{
object o = keyword_kinds[name];
if (o != null) return (KeywordKind)o;
else return KeywordKind.None;
if (KeywordsStorage.KeywordKinds.TryGetValue(name, out var kind))
return kind;
else
return KeywordKind.None;
}
@ -2526,7 +2474,7 @@ namespace PascalABCCompiler.Parsers
sb.AppendLine(lineText);
sb.AppendLine("begin end;");
sb.AppendLine("begin end.");
program_module node = this.parser.GetCompilationUnit("test.pas", sb.ToString(), null, null, ParseMode.Special) as program_module;
program_module node = this.Parser.GetCompilationUnit("test.pas", sb.ToString(), null, null, ParseMode.Special) as program_module;
procedure_header header = (node.program_block.defs.defs[0] as procedure_definition).proc_header;
get_procedure_template(header, res, col);
return res.ToString();
@ -2537,7 +2485,7 @@ namespace PascalABCCompiler.Parsers
sb.AppendLine(lineText);
sb.AppendLine("begin end;");
sb.AppendLine("begin end.");
program_module node = this.parser.GetCompilationUnit("test.pas", sb.ToString(), null, null, ParseMode.Special) as program_module;
program_module node = this.Parser.GetCompilationUnit("test.pas", sb.ToString(), null, null, ParseMode.Special) as program_module;
if (node.program_block.defs != null && node.program_block.defs.defs.Count > 0 && node.program_block.defs.defs[0] is procedure_definition)
{
procedure_header header = (node.program_block.defs.defs[0] as procedure_definition).proc_header;
@ -2718,7 +2666,7 @@ namespace PascalABCCompiler.Parsers
{
keyword = KeywordKind.Raise;
}
else if (keywords.ContainsKey(s))
else if (IsKeyword(s))
{
keyword = KeywordKind.CommonKeyword;
}
@ -3115,11 +3063,15 @@ namespace PascalABCCompiler.Parsers
public virtual string FindExpressionFromAnyPosition(int off, string Text, int line, int col, out KeywordKind keyw, out string expr_without_brackets)
{
int i = off - 1;
// это например вызов метода без параметров
expr_without_brackets = null;
keyw = KeywordKind.None;
if (i < 0)
return "";
bool is_char = false;
// идем в обе стороны от off
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (Text[i] != ' ' && (Char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '?' && IsPunctuation(Text, i + 1) || Text[i] == '!'))
{
@ -3792,8 +3744,8 @@ namespace PascalABCCompiler.Parsers
}
}
public class CLanguageInformation : DefaultLanguageInformation
#region LEGACY - C language
/*public class CLanguageInformation : DefaultLanguageInformation
{
public CLanguageInformation(IParser p)
{
@ -3941,18 +3893,18 @@ namespace PascalABCCompiler.Parsers
sb.Append(ctn.Name.Substring(0,ctn.Name.IndexOf('`')));
sb.Append('<');
sb.Append('>');
/*sb.Append('<');
*//*sb.Append('<');
for (int i=0; i<len; i++)
{
sb.Append('T');
if (i<len-1)
sb.Append(',');
}
sb.Append('>');*/
sb.Append('>');*//*
return sb.ToString();
}
//if (ctn.IsArray) return "array of "+GetTypeName(ctn.GetElementType());
//if (ctn == Type.GetType("System.Void*")) return StringConstants.pointer_type_name;
//if (ctn == Type.GetType("System.Void*")) return PascalABCCompiler.StringConstants.pointer_type_name;
return ctn.Name;
}
@ -4199,6 +4151,7 @@ namespace PascalABCCompiler.Parsers
sb.Append(')');
return sb.ToString();
}
}
}*/
#endregion
}

View file

@ -21,7 +21,7 @@ namespace VisualPascalABC
public CodeFileDocumentTextEditorControl()
{
editactions[Keys.Space | Keys.Control] = new CodeCompletionAllNamesAction();
editactions[Keys.Space | Keys.Shift] = new CodeCompletionNamesOnlyInModuleAction();
editactions[Keys.Space | Keys.Shift] = new CodeCompletionShiftSpaceActions();
editactions[Keys.Enter | Keys.Control] = new GotoAction();
editactions[Keys.LButton | Keys.Control] = new GotoAction();
editactions[Keys.C | Keys.Shift | Keys.Control] = new ClassOrMethodRealizationAction();

View file

@ -118,22 +118,39 @@ namespace VisualPascalABC
public static List<Position> GetDefinitionPosition(TextArea textArea, bool only_check)
{
if (CodeCompletion.CodeCompletionController.CurrentParser == null) return new List<Position>();
IParser parser = CodeCompletion.CodeCompletionController.CurrentParser;
if (parser == null)
return new List<Position>();
IDocument doc = textArea.Document;
string textContent = doc.TextContent;
ccp = new CodeCompletionProvider();
string full_expr;
string expressionResult = FindFullExpression(textContent, textArea, out ccp.keyword, out full_expr);
if (expressionResult != null)
expressionResult = expressionResult.Trim();
// Проверка, что компилируем Паскаль временно EVA 10.11.2024
if (parser == Languages.Facade.LanguageProvider.Instance.SelectLanguageByName(StringConstants.pascalLanguageName).Parser)
{
if (expressionResult != full_expr && full_expr.StartsWith("("))
return new List<Position>();
if (full_expr != null && full_expr.Contains("^"))
full_expr = full_expr.Replace("^","");
{
full_expr = full_expr.Replace("^", "");
}
}
List<Position> poses = ccp.GetDefinition(full_expr, textArea.MotherTextEditorControl.FileName, textArea.Caret.Line, textArea.Caret.Column, only_check);
if (poses == null || poses.Count == 0)
poses = ccp.GetDefinition(expressionResult, textArea.MotherTextEditorControl.FileName, textArea.Caret.Line, textArea.Caret.Column, only_check);
return poses;
}
@ -574,12 +591,93 @@ namespace VisualPascalABC
}
}
public class CodeCompletionNamesOnlyInModuleAction : CodeCompletionAllNamesAction
/// <summary>
/// Включает в себя три различных действия по shift + space, что не очень хорошо EVA
/// </summary>
public class CodeCompletionShiftSpaceActions : ICSharpCode.TextEditor.Actions.AbstractEditAction
{
PABCNETCodeCompletionWindow codeCompletionWindow;
public static TextArea textArea = CodeCompletionAllNamesAction.textArea;
public static Hashtable comp_windows = CodeCompletionAllNamesAction.comp_windows;
public static bool is_begin = false;
private string get_prev_text(string text, int off)
{
StringBuilder sb = new StringBuilder();
while (off >= 0 && char.IsLetterOrDigit(text[off]))
{
sb.Insert(0, text[off--]);
}
return sb.ToString();
}
public override void Execute(TextArea _textArea)
{
key = '\0';
base.Execute(_textArea);
//base.Execute(_textArea);
textArea = _textArea;
int off = textArea.Caret.Offset;
string text = textArea.Document.TextContent.Substring(0, textArea.Caret.Offset);
// автодополнение xml-комментария
if (off > 2 && text[off - 1] == '/' && text[off - 2] == '/' && text[off - 3] == '/')
{
CodeCompletionActionsManager.GenerateCommentTemplate(textArea);
return;
}
// автодополнение некоторого выражения из файла template.pct
else
{
string prev = get_prev_text(text, off - 1);
if (!string.IsNullOrEmpty(prev))
{
CodeCompletionActionsManager.GenerateTemplate(prev, textArea);
return;
}
}
// если подсказка по точке выключена дальше не идем
if (!WorkbenchServiceFactory.Workbench.UserOptions.CodeCompletionDot)
return;
if (CodeCompletion.CodeCompletionController.CurrentParser == null)
return;
is_begin = true;
codeCompletionWindow = PABCNETCodeCompletionWindow.ShowCompletionWindow(
VisualPABCSingleton.MainForm, // The parent window for the completion window
textArea.MotherTextEditorControl, // The text editor to show the window for
textArea.MotherTextEditorControl.FileName, // Filename - will be passed back to the provider
new CodeCompletionProvider(), // Provider to get the list of possible completions
'\0', // Key pressed - will be passed to the provider
false,
false,
KeywordKind.None
);
comp_windows[textArea] = codeCompletionWindow;
if (codeCompletionWindow != null)
{
// ShowCompletionWindow can return null when the provider returns an empty list
codeCompletionWindow.Closed += new EventHandler(OnCodeCompletionWindowClosed);
}
}
// такой же метод есть в CodeCompletionKeyHandler EVA
public void OnCodeCompletionWindowClosed(object sender, EventArgs e)
{
if (codeCompletionWindow != null)
{
codeCompletionWindow.Closed -= new EventHandler(OnCodeCompletionWindowClosed);
CodeCompletionProvider.disp.Reset();
CodeCompletion.AssemblyDocCache.Reset();
CodeCompletion.UnitDocCache.Reset();
codeCompletionWindow.Dispose();
codeCompletionWindow = null;
}
comp_windows[textArea] = null;
}
}
@ -627,18 +725,6 @@ namespace VisualPascalABC
PABCNETCodeCompletionWindow codeCompletionWindow;
public static TextArea textArea;
public static Hashtable comp_windows = new Hashtable();
public static bool is_begin = false;
protected char key = '_';
private string get_prev_text(string text, int off)
{
StringBuilder sb = new StringBuilder();
while (off >= 0 && char.IsLetterOrDigit(text[off]))
{
sb.Insert(0, text[off--]);
}
return sb.ToString();
}
public override void Execute(TextArea _textArea)
{
@ -647,52 +733,31 @@ namespace VisualPascalABC
textArea = _textArea;
int off = textArea.Caret.Offset;
string text = textArea.Document.TextContent.Substring(0, textArea.Caret.Offset);
if (key == '\0')
if (off > 2 && text[off - 1] == '/' && text[off - 2] == '/' && text[off - 3] == '/')
{
CodeCompletionActionsManager.GenerateCommentTemplate(textArea);
return;
}
else
{
string prev = get_prev_text(text, off - 1);
if (!string.IsNullOrEmpty(prev))
{
CodeCompletionActionsManager.GenerateTemplate(prev, textArea);
return;
}
}
if (!WorkbenchServiceFactory.Workbench.UserOptions.CodeCompletionDot)
return;
if (CodeCompletion.CodeCompletionController.CurrentParser == null) return;
CodeCompletionProvider completionDataProvider = new CodeCompletionProvider();
bool is_pattern = false;
completionDataProvider.preSelection = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.FindPattern(off, text, out var is_pattern);
is_begin = true;
completionDataProvider.preSelection = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.FindPattern(off, text, out is_pattern);
if (!is_pattern && off > 0 && text[off - 1] == '.')
key = '$';
codeCompletionWindow = PABCNETCodeCompletionWindow.ShowCompletionWindow(
VisualPABCSingleton.MainForm, // The parent window for the completion window
textArea.MotherTextEditorControl, // The text editor to show the window for
textArea.MotherTextEditorControl.FileName, // Filename - will be passed back to the provider
completionDataProvider, // Provider to get the list of possible completions
key, // Key pressed - will be passed to the provider
'_', // Key pressed - will be passed to the provider
false,
false,
PascalABCCompiler.Parsers.KeywordKind.None
KeywordKind.None
);
key = '_';
CodeCompletionNamesOnlyInModuleAction.comp_windows[textArea] = codeCompletionWindow;
CodeCompletionShiftSpaceActions.comp_windows[textArea] = codeCompletionWindow;
if (codeCompletionWindow != null)
{
// ShowCompletionWindow can return null when the provider returns an empty list
codeCompletionWindow.Closed += new EventHandler(CloseCodeCompletionWindow);
codeCompletionWindow.Closed += new EventHandler(OnCodeCompletionWindowClosed);
}
}
//catch (Exception e)
@ -701,11 +766,12 @@ namespace VisualPascalABC
}
}
public void CloseCodeCompletionWindow(object sender, EventArgs e)
// такой же метод есть в CodeCompletionKeyHandler EVA
public void OnCodeCompletionWindowClosed(object sender, EventArgs e)
{
if (codeCompletionWindow != null)
{
codeCompletionWindow.Closed -= new EventHandler(CloseCodeCompletionWindow);
codeCompletionWindow.Closed -= new EventHandler(OnCodeCompletionWindowClosed);
CodeCompletionProvider.disp.Reset();
CodeCompletion.AssemblyDocCache.Reset();
CodeCompletion.UnitDocCache.Reset();

View file

@ -1,4 +1,4 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// 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 System;
using System.Collections;
@ -40,7 +40,7 @@ namespace VisualPascalABC
//editor.ActiveTextAreaControl.TextArea.KeyDown += new System.Windows.Forms.KeyEventHandler(TextArea_KeyDown);
//editor.ActiveTextAreaControl.KeyDown += h.TextControlEventHandler;
// When the editor is disposed, close the code completion window
editor.Disposed += h.CloseCodeCompletionWindow;
editor.Disposed += h.OnCodeCompletionWindowClosed;
return h;
}
@ -74,11 +74,11 @@ namespace VisualPascalABC
}
else
{
PABCNETCodeCompletionWindow ccw = CodeCompletionNamesOnlyInModuleAction.comp_windows[editor.ActiveTextAreaControl.TextArea] as PABCNETCodeCompletionWindow;
PABCNETCodeCompletionWindow ccw = CodeCompletionShiftSpaceActions.comp_windows[editor.ActiveTextAreaControl.TextArea] as PABCNETCodeCompletionWindow;
if (ccw != null && CodeCompletionNamesOnlyInModuleAction.is_begin)
if (ccw != null && CodeCompletionShiftSpaceActions.is_begin)
{
CodeCompletionNamesOnlyInModuleAction.is_begin = false;
CodeCompletionShiftSpaceActions.is_begin = false;
if (key != ' ')
ccw.ProcessKeyEvent(key);
else
@ -115,10 +115,10 @@ namespace VisualPascalABC
true,
PascalABCCompiler.Parsers.KeywordKind.None
);
CodeCompletionNamesOnlyInModuleAction.is_begin = true;
CodeCompletionNamesOnlyInModuleAction.comp_windows[editor.ActiveTextAreaControl.TextArea] = codeCompletionWindow;
CodeCompletionShiftSpaceActions.is_begin = true;
CodeCompletionShiftSpaceActions.comp_windows[editor.ActiveTextAreaControl.TextArea] = codeCompletionWindow;
if (codeCompletionWindow != null)
codeCompletionWindow.Closed += new EventHandler(CloseCodeCompletionWindow);
codeCompletionWindow.Closed += new EventHandler(OnCodeCompletionWindowClosed);
}
}
else if (key == '(' || key == '[' || key == ',')
@ -131,7 +131,7 @@ namespace VisualPascalABC
{
insightWindow = new PABCNETInsightWindow(VisualPABCSingleton.MainForm, editor);
insightWindow.Font = new Font(Constants.CompletionInsightWindowFontName, insightWindow.Font.Size);
insightWindow.Closed += new EventHandler(CloseInsightWindow);
insightWindow.Closed += new EventHandler(OnInsightWindowClosed);
}
else
{
@ -162,9 +162,9 @@ namespace VisualPascalABC
false,
keyw
);
CodeCompletionNamesOnlyInModuleAction.comp_windows[editor.ActiveTextAreaControl.TextArea] = codeCompletionWindow;
CodeCompletionShiftSpaceActions.comp_windows[editor.ActiveTextAreaControl.TextArea] = codeCompletionWindow;
if (codeCompletionWindow != null)
codeCompletionWindow.Closed += new EventHandler(CloseCodeCompletionWindow);
codeCompletionWindow.Closed += new EventHandler(OnCodeCompletionWindowClosed);
//return true;
}
}
@ -198,8 +198,10 @@ namespace VisualPascalABC
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsDefinitionIdentifierAfterKeyword(keyw))
return false;
// если не первый символ выражения (предыдущий тоже буква или "_"), то не открываем новое окно
if (editor.ActiveTextAreaControl.TextArea.Caret.Offset > 0 && (char.IsLetterOrDigit(editor.Document.TextContent[editor.ActiveTextAreaControl.TextArea.Caret.Offset - 1]) || editor.Document.TextContent[editor.ActiveTextAreaControl.TextArea.Caret.Offset - 1] == '_'))
return false;
completionDataProvider = new CodeCompletionProvider();
codeCompletionWindow = PABCNETCodeCompletionWindow.ShowCompletionWindowWithFirstChar(
VisualPABCSingleton.MainForm, // The parent window for the completion window
@ -209,9 +211,9 @@ namespace VisualPascalABC
key, // Key pressed - will be passed to the provider
keyw
);
CodeCompletionNamesOnlyInModuleAction.comp_windows[editor.ActiveTextAreaControl.TextArea] = codeCompletionWindow;
CodeCompletionShiftSpaceActions.comp_windows[editor.ActiveTextAreaControl.TextArea] = codeCompletionWindow;
if (codeCompletionWindow != null)
codeCompletionWindow.Closed += new EventHandler(CloseCodeCompletionWindow);
codeCompletionWindow.Closed += new EventHandler(OnCodeCompletionWindowClosed);
}
}
@ -253,26 +255,26 @@ namespace VisualPascalABC
return false;
}
void CloseInsightWindow(object sender, EventArgs e)
void OnInsightWindowClosed(object sender, EventArgs e)
{
if (insightWindow != null)
{
insightWindow.Closed -= new EventHandler(CloseInsightWindow);
insightWindow.Closed -= new EventHandler(OnInsightWindowClosed);
insightWindow.Dispose();
insightWindow = null;
}
}
void CloseCodeCompletionWindow(object sender, EventArgs e)
void OnCodeCompletionWindowClosed(object sender, EventArgs e)
{
if (codeCompletionWindow != null)
{
codeCompletionWindow.Closed -= new EventHandler(CloseCodeCompletionWindow);
codeCompletionWindow.Closed -= new EventHandler(OnCodeCompletionWindowClosed);
CodeCompletionProvider.disp.Reset();
CodeCompletion.AssemblyDocCache.Reset();
CodeCompletion.UnitDocCache.Reset();
codeCompletionWindow.Dispose();
CodeCompletionNamesOnlyInModuleAction.comp_windows[editor.ActiveTextAreaControl.TextArea] = null;
CodeCompletionShiftSpaceActions.comp_windows[editor.ActiveTextAreaControl.TextArea] = null;
codeCompletionWindow = null;
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// 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 System;
using System.Collections;
@ -9,6 +9,7 @@ using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using PascalABCCompiler.Parsers;
using Languages.Facade;
using System.Linq;
namespace VisualPascalABC
{
@ -113,12 +114,6 @@ namespace VisualPascalABC
if (VisualPABCSingleton.MainForm.VisualEnvironmentCompiler.compilerLoaded)
e = language.Parser.GetExpression("test" + System.IO.Path.GetExtension(fileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
if (e is PascalABCCompiler.SyntaxTree.bin_expr && expr.Contains("<"))
{
expr = expr.Replace("<","&<");
Errors.Clear();
e = language.Parser.GetExpression("test" + System.IO.Path.GetExtension(fileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
}
if (e == null)
return loc;
CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName];
@ -321,11 +316,118 @@ namespace VisualPascalABC
return expr;
}
public ICompletionData[] GetCompletionDataByFirst(int off, string Text, int line, int col, char charTyped, PascalABCCompiler.Parsers.KeywordKind keyw)
/// <summary>
/// Возвращает подсказки определяемые первым символом выражения, введенного пользователем
/// </summary>
public ICompletionData[] GetCompletionDataByFirst(int line, int col, char charTyped, KeywordKind keyw)
{
List<ICompletionData> resultList = new List<ICompletionData>();
List<ICompletionData> lst = new List<ICompletionData>();
try
{
ILanguageInformation languageInformation = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation;
List<string> keywords;
bool isTypeAfterKeyword = false;
// если по смыслу должен вводиться тип данных
if (languageInformation.IsTypeAfterKeyword(keyw))
{
keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetTypeKeywords();
isTypeAfterKeyword = true;
}
else
{
keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
}
bool isNamespaceAfterKeyword = false;
// конструкция типа "uses"
if (languageInformation.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)
{
bool languageCaseSensitive = LanguageProvider.Instance.SelectLanguageByExtension(FileName).CaseSensitive;
AddCompletionDatasByFirstForSymInfos(resultList, charTyped, symInfos, languageCaseSensitive);
//resultList.Sort();
//defaultCompletionElement = resultList[0] as DefaultCompletionData;
}
}
catch (Exception) { }
this.ByFirstChar = true;
return resultList.ToArray();
}
/// <summary>
/// Добавляет в resultList (итоговый список подсказок) данные, соответствующие переданному массиву типа SymInfo[].
/// Используется для случая ввода пользователем первого символа выражения
/// </summary>
private void AddCompletionDatasByFirstForSymInfos(List<ICompletionData> resultList, char charTyped, SymInfo[] symInfos, bool languageCaseSensitive)
{
HashSet<string> symbolsAdded = languageCaseSensitive ? new HashSet<string>() : new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
List<ICompletionData> candidatesForDefault = new List<ICompletionData>();
bool stop = false;
ICompletionData lastUsedItem = CompletionDataDispatcher.GetLastUsedItem(charTyped);
foreach (SymInfo symInfo in symInfos)
{
if (symInfo == null || symInfo.not_include) continue;
if (symbolsAdded.Contains(symInfo.name))
continue;
UserDefaultCompletionData completionData = new UserDefaultCompletionData(symInfo.name, symInfo.description, ImagesProvider.GetPictureNum(symInfo), false);
StringComparison stringComparison = languageCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
// если мы выбирали что-то раньше из списка подсказок, то считаем это элементом по умолчанию
if (!stop && lastUsedItem != null && string.Equals(symInfo.name, lastUsedItem.Text, stringComparison))
{
defaultCompletionElement = completionData;
stop = true;
}
// иначе формируем список подходящих подсказок - "кандидатов" для элемента по умолчанию
else if (!stop && lastUsedItem == null && symInfo.name.StartsWith(charTyped.ToString(), stringComparison))
{
//defaultCompletionElement = ddd;
candidatesForDefault.Add(completionData);
//stop = true;
}
disp.Add(symInfo, completionData);
resultList.Add(completionData);
symbolsAdded.Add(symInfo.name);
}
if (candidatesForDefault.Count > 0)
defaultCompletionElement = candidatesForDefault.Min() as UserDefaultCompletionData; // здесь выбирается минимальное по длине
}
/// <summary>
/// Формирует массив данных из таблицы символов для подсказок в случае введения пользователем первой буквы выражения
/// </summary>
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
@ -334,238 +436,292 @@ namespace VisualPascalABC
dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[CodeCompletion.CodeCompletionNameHelper.system_unit_file_full_name];
special_module = true;
}*/
string pattern = charTyped.ToString();
string[] keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsTypeAfterKeyword(keyw))
SymInfo[] symInfos = null;
if (dconv == null)
{
keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetTypeKeywords();
}
if (!CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsNamespaceAfterKeyword(keyw))
foreach (string key in keywords)
if (isNamespaceAfterKeyword)
{
//if (key.StartsWith(pattern, StringComparison.CurrentCultureIgnoreCase))
resultList.Add(new UserDefaultCompletionData(key, null, ImagesProvider.IconNumberKeyword, false));
symInfos = CodeCompletion.DomConverter.standard_units;
}
PascalABCCompiler.Parsers.SymInfo[] mis = null;
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsNamespaceAfterKeyword(keyw))
{
mis = CodeCompletion.DomConverter.standard_units;
}
if (dconv != null)
else
{
//if (keyw == PascalABCCompiler.Parsers.KeywordKind.Colon || keyw == PascalABCCompiler.Parsers.KeywordKind.Of || keyw == PascalABCCompiler.Parsers.KeywordKind.TypeDecl)
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsTypeAfterKeyword(keyw))
mis = dconv.GetTypeByPattern(pattern, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
else if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsNamespaceAfterKeyword(keyw) && mis == null)
mis = dconv.GetNamespaces();
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
mis = dconv.GetNameByPattern(null, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
symInfos = CodeCompletion.DomConverter.standard_units;
}
Hashtable cache = new Hashtable();
if (mis != null)
else
{
bool stop = false;
ICompletionData data = CompletionDataDispatcher.GetLastUsedItem(charTyped);
foreach (PascalABCCompiler.Parsers.SymInfo mi in mis)
{
if (mi.not_include) continue;
if (cache.Contains(mi.name))
continue;
UserDefaultCompletionData ddd = new UserDefaultCompletionData(mi.name, mi.description, ImagesProvider.GetPictureNum(mi), false);
if (!stop && data != null && string.Compare(mi.name, data.Text, true) == 0)
{
defaultCompletionElement = ddd;
stop = true;
// интересно, что передается pattern = null EVA
symInfos = dconv.GetNameByPattern(null, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
}
else if (!stop && data == null && mi.name.StartsWith(charTyped.ToString(), StringComparison.CurrentCultureIgnoreCase))
{
//defaultCompletionElement = ddd;
lst.Add(ddd);
//stop = true;
}
disp.Add(mi, ddd);
resultList.Add(ddd);
cache[mi.name] = mi;
}
//resultList.Sort();
//defaultCompletionElement = resultList[0] as DefaultCompletionData;
}
}
catch (Exception e)
{
}
lst.Sort();
if (lst.Count > 0) defaultCompletionElement = lst[0] as UserDefaultCompletionData;
ICompletionData[] res_arr = resultList.ToArray();
this.ByFirstChar = true;
return res_arr;
return symInfos;
}
public ICompletionData[] GetCompletionData(int off, string Text, int line, int col, char charTyped, PascalABCCompiler.Parsers.KeywordKind keyw)
/// <summary>
/// Вспомогательная струтура для метода GetCompletionData, хранит информацию о действиях пользователя
/// </summary>
private struct ActionContext
{
public bool dotPressed;
public bool ctrlSpace;
public bool shiftSpace;
public bool spaceAfterNew;
public bool spaceAfterUses;
}
/// <summary>
/// Возвращает массив подсказок для случая нажатия пользователем "триггерной" клавиши
/// </summary>
public ICompletionData[] GetCompletionData(int off, string text, int line, int col, char charTyped, KeywordKind keywordKind)
{
List<ICompletionData> resultList = new List<ICompletionData>();
try
{
string pattern = null;
string expr = null;
bool ctrl_space = charTyped == '\0' || charTyped == '_';
bool shift_space = charTyped == '\0';
bool inside_dot_pattern = false;
bool new_space = keyw == PascalABCCompiler.Parsers.KeywordKind.New;
if (ctrl_space)
// поменять на обращение к CodeCompletionController.CurrentLanguage
ILanguage currentLanguage = LanguageProvider.Instance.SelectLanguageByExtension(FileName);
var context = new ActionContext()
{
bool is_pattern = false;
pattern = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.FindPattern(off, Text, out is_pattern);
if (is_pattern && Text[off - pattern.Length - 1] == '.')
dotPressed = charTyped == '.',
ctrlSpace = charTyped == '_',
shiftSpace = charTyped == '\0',
spaceAfterNew = keywordKind == KeywordKind.New,
spaceAfterUses = keywordKind == KeywordKind.Uses
};
string expressionText = GetExpressionTextForCompletionData(off, text, line, col,
currentLanguage.LanguageInformation, in context, out var insidePatternWithDots, out var ctrlOrShiftSpaceAfterDot, out var pattern);
// добавляем ключевые слова в случае "ctrl + space", нажатых в "пустом" месте
if (!ctrlOrShiftSpaceAfterDot && context.ctrlSpace && string.IsNullOrEmpty(pattern))
{
inside_dot_pattern = true;
expr = FindExpression(off - pattern.Length - 1, Text, line, col);
var keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
resultList.AddRange(keywords.Select(keyword =>
new UserDefaultCompletionData(keyword, null, ImagesProvider.IconNumberKeyword, false)));
}
}
else if (new_space)
PascalABCCompiler.SyntaxTree.expression expr = null;
// для "ctrl + space" и "shift + space" дерево expression не требуется (кроме случая insidePatternWithDots)
if ((context.dotPressed || context.spaceAfterNew || context.spaceAfterUses || insidePatternWithDots) && expressionText != null)
{
expr = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.SkipNew(off - 1, Text, ref keyword);
}
else
if (!new_space && keyw != PascalABCCompiler.Parsers.KeywordKind.Uses)
if (charTyped != '$')
expr = FindExpression(off, Text, line, col);
else
expr = FindExpression(off - 1, Text, line, col);
List<PascalABCCompiler.Errors.Error> Errors = new List<PascalABCCompiler.Errors.Error>();
PascalABCCompiler.SyntaxTree.expression e = null;
if (ctrl_space && !shift_space && (pattern == null || pattern == ""))
{
string[] keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
foreach (string key in keywords)
{
//if (key.StartsWith(pattern, StringComparison.CurrentCultureIgnoreCase))
resultList.Add(new UserDefaultCompletionData(key, null, ImagesProvider.IconNumberKeyword, false));
}
expr = GetExpressionForCompletionData(currentLanguage.Parser,
in context, expressionText, insidePatternWithDots, out var shouldReturnNull);
if (shouldReturnNull)
return null;
}
ILanguage currentLanguage = LanguageProvider.Instance.SelectLanguageByExtensionSafe(FileName);
SymInfo[] symInfos = GetSymInfosForCompletionData(line, col, in context, currentLanguage.CaseSensitive,
expressionText, ctrlOrShiftSpaceAfterDot, insidePatternWithDots, pattern, expr, out var selectedSymInfo, out var lastUsedMember, out var shouldReturnNull2);
if (currentLanguage == null)
if (shouldReturnNull2)
return null;
if ((!ctrl_space || inside_dot_pattern) && expr != null)
if (symInfos != null)
{
e = currentLanguage.Parser.GetTypeAsExpression("test" + System.IO.Path.GetExtension(FileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
if (e == null)
{
Errors.Clear();
e = currentLanguage.Parser.GetExpression("test" + System.IO.Path.GetExtension(FileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
AddCompletionDatasForSymInfos(resultList, currentLanguage.CaseSensitive, symInfos, selectedSymInfo, lastUsedMember);
}
if ((e == null || Errors.Count > 0) && !new_space) return null;
}
SymInfo[] mis = null;
CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[FileName];
if (dconv == null)
{
if (keyw == PascalABCCompiler.Parsers.KeywordKind.Uses)
mis = CodeCompletion.DomConverter.standard_units;
else if (!ctrl_space)
return new ICompletionData[0];
}
string fname = FileName;
SymInfo sel_si = null;
string last_used_member = null;
if (dconv != null)
{
if (new_space)
mis = dconv.GetTypes(e, line, col, out sel_si);
else if (keyw == PascalABCCompiler.Parsers.KeywordKind.Uses && mis == null)
{
if (WorkbenchServiceFactory.Workbench.UserOptions.EnableSmartIntellisense)
mis = dconv.GetNamespaces();
else
mis = CodeCompletion.DomConverter.standard_units;
catch (Exception) { }
return resultList.ToArray();
}
else
if (!ctrl_space)
/// <summary>
/// Добавляет в resultList (итоговый список подсказок) данные, соответствующие переданному массиву типа SymInfo[].
/// Используется для случая нажатия пользователем "триггерной" клавиши
/// </summary>
private void AddCompletionDatasForSymInfos(List<ICompletionData> resultList, bool languageCaseSensitive, SymInfo[] symInfos, SymInfo selectedSymInfo, string lastUsedMember)
{
CodeCompletion.SymScope dot_sc = null;
mis = dconv.GetName(e, expr, line, col, keyword, ref dot_sc);
if (dot_sc != null && VisualPABCSingleton.MainForm.UserOptions.EnableSmartIntellisense)
{
CompletionDataDispatcher.AddMemberBeforeDot(dot_sc);
last_used_member = CompletionDataDispatcher.GetRecentUsedMember(dot_sc);
}
}
else
{
CodeCompletion.SymScope dot_sc = null;
if (inside_dot_pattern)
{
List<SymInfo> si_list = new List<SymInfo>();
SymInfo[] from_list = dconv.GetName(e, expr, line, col, keyword, ref dot_sc);
for (int i = 0; i < from_list.Length; i++)
{
if (from_list[i].name.StartsWith(pattern, StringComparison.OrdinalIgnoreCase))
si_list.Add(from_list[i]);
}
mis = si_list.ToArray();
}
// ICompletionData data = null;
else
mis = dconv.GetNameByPattern(pattern, line, col, charTyped == '_', VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
}
HashSet<string> symbolsAdded = languageCaseSensitive ? new HashSet<string>() : new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
}
Hashtable cache = null;
if (!currentLanguage.CaseSensitive)
cache = new Hashtable(StringComparer.CurrentCultureIgnoreCase);
else
cache = new Hashtable();
int num = 0;
if (mis != null)
foreach (SymInfo symInfo in symInfos)
{
bool stop = false;
ICompletionData data = null;
foreach (SymInfo mi in mis)
{
if (mi == null || mi.not_include) continue;
if (cache.Contains(mi.name + mi.kind))
if (symInfo == null || symInfo.not_include)
continue;
UserDefaultCompletionData ddd = new UserDefaultCompletionData(mi.addit_name != null ? mi.addit_name : mi.name, mi.description, ImagesProvider.GetPictureNum(mi), false);
if (symbolsAdded.Contains(symInfo.name + symInfo.kind))
continue;
UserDefaultCompletionData completionData = new UserDefaultCompletionData(
symInfo.addit_name != null ? symInfo.addit_name : symInfo.name,
symInfo.description, ImagesProvider.GetPictureNum(symInfo), false
);
disp.Add(symInfo, completionData);
resultList.Add(completionData);
symbolsAdded.Add(symInfo.name + symInfo.kind);
disp.Add(mi, ddd);
resultList.Add(ddd);
cache[mi.name + mi.kind] = mi;
/*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 (last_used_member != null && last_used_member == mi.name)
if (lastUsedMember != null && lastUsedMember == symInfo.name || selectedSymInfo != null && symInfo == selectedSymInfo)
{
defaultCompletionElement = ddd;
}
if (sel_si != null && mi == sel_si)
{
defaultCompletionElement = ddd;
stop = true;
defaultCompletionElement = completionData;
}
}
if (defaultCompletionElement == null && data != null)
defaultCompletionElement = data as UserDefaultCompletionData;
/*if (defaultCompletionElement == null && data != null)
defaultCompletionElement = data as UserDefaultCompletionData;*/
}
/// <summary>
/// Формирует массив данных из таблицы символов для подсказок в случае нажатия пользователем "триггерной" клавиши
/// (в зависимости от введенного выражения и другого контекста)
/// </summary>
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);
}
}
catch (Exception e)
// ctrl + space после некоторого выражения
else if (context.ctrlSpace) // context.chiftSpace здесь не может быть true, поскольку такие ситуации обрабатываются в ShiftSpaceActions.Execute()
{
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();
}
return resultList.ToArray();
else
symInfos = dconv.GetNameByPattern(pattern, line, col, context.ctrlSpace, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
}
}
return symInfos;
}
/// <summary>
/// Возвращает дерево выражения, введенного пользователем перед нажатием "триггерной" клавиши
/// </summary>
private PascalABCCompiler.SyntaxTree.expression GetExpressionForCompletionData(IParser parser, in ActionContext context, string expressionText, bool insidePatternWithDots, out bool shouldReturnNull)
{
shouldReturnNull = false;
List<PascalABCCompiler.Errors.Error> Errors = new List<PascalABCCompiler.Errors.Error>();
List<PascalABCCompiler.Errors.CompilerWarning> Warnings = new List<PascalABCCompiler.Errors.CompilerWarning>();
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;
}
/// <summary>
/// Получение текста выражения, введенного пользователем перед нажатием "триггерной" клавиши
/// </summary>
private string GetExpressionTextForCompletionData(int off, string text, int line, int col, ILanguageInformation languageInformation, 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 = languageInformation.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 = languageInformation.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;
@ -636,11 +792,11 @@ namespace VisualPascalABC
public ICompletionData[] GenerateCompletionDataByFirstChar(string fileName, TextArea textArea, char charTyped, PascalABCCompiler.Parsers.KeywordKind keyw)
{
controller = new CodeCompletion.CodeCompletionController();
int off = textArea.Caret.Offset;
// 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(off, text, textArea.Caret.Line, textArea.Caret.Column, charTyped, keyw);
ICompletionData[] data = GetCompletionDataByFirst(textArea.Caret.Line, textArea.Caret.Column, charTyped, keyw);
CodeCompletion.AssemblyDocCache.CompleteDocumentation();
CodeCompletion.UnitDocCache.CompleteDocumentation();
controller = null;

View file

@ -11,6 +11,7 @@ namespace VisualPascalABC
{
public Dictionary<string, string> ht = new Dictionary<string, string>();
// TODO: Требуется адаптация к многоязычности EVA
public CodeTemplateManager(string filename = "template.pct", bool searchFromLocalDirectory = false)
{
try

View file

@ -4,14 +4,10 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using Languages.Integration;
using PascalABCCompiler.Parsers;
namespace VisualPascalABC
@ -22,65 +18,68 @@ namespace VisualPascalABC
private static string GetPopupHintText(TextArea textArea, ToolTipRequestEventArgs e)
{
ICSharpCode.TextEditor.TextLocation logicPos = e.LogicalPosition;
TextLocation logicPos = e.LogicalPosition;
IDocument doc = textArea.Document;
LineSegment seg = doc.GetLineSegment(logicPos.Y);
string FileName = textArea.MotherTextEditorControl.FileName;
PascalABCCompiler.Parsers.KeywordKind keyw = PascalABCCompiler.Parsers.KeywordKind.None;
if (logicPos.X > seg.Length - 1)
LineSegment lineSegment = doc.GetLineSegment(logicPos.Y);
string fileName = textArea.MotherTextEditorControl.FileName;
if (logicPos.X > lineSegment.Length - 1)
return null;
//string expr = FindFullExpression(doc.TextContent, seg.Offset + logicPos.X,e.LogicalPosition.Line,e.LogicalPosition.Column);
string expr_without_brackets = null;
string expr = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.FindExpressionFromAnyPosition(seg.Offset + logicPos.X, doc.TextContent, e.LogicalPosition.Line, e.LogicalPosition.Column, out keyw, out expr_without_brackets);
IParser parser = CodeCompletion.CodeCompletionController.CurrentParser;
string expr = parser.LanguageInformation.FindExpressionFromAnyPosition(
lineSegment.Offset + logicPos.X, doc.TextContent, e.LogicalPosition.Line, e.LogicalPosition.Column, out var keyw, out var exprWithoutBrackets);
// пока непонятно, когда такое может быть EVA
if (expr == null)
expr = exprWithoutBrackets;
if (expr == null)
expr = expr_without_brackets;
if (expr_without_brackets == null)
return null;
List<PascalABCCompiler.Errors.Error> Errors = new List<PascalABCCompiler.Errors.Error>();
List<PascalABCCompiler.Errors.CompilerWarning> Warnings = new List<PascalABCCompiler.Errors.CompilerWarning>();
IParser parser = Languages.Facade.LanguageProvider.Instance.SelectLanguageByExtension(FileName).Parser;
PascalABCCompiler.SyntaxTree.expression expressionTree = parser.GetExpression("test" + Path.GetExtension(fileName),
expr, Errors, Warnings);
PascalABCCompiler.SyntaxTree.expression tree = parser.GetExpression("test" + Path.GetExtension(FileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
bool header = false;
if (Errors.Count > 0)
{
if (expr.IndexOf('<') != -1 && expr.IndexOf('>') != -1)
{
Errors.Clear();
tree = parser.GetExpression("test" + Path.GetExtension(FileName), expr.Replace("<", "&<"), Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
}
else
// Пока добавили проверку, что анализируем Паскаль EVA
if (Errors.Count > 0 && parser == Languages.Facade.LanguageProvider.Instance.SelectLanguageByName(PascalABCCompiler.StringConstants.pascalLanguageName).Parser)
{
string s = expr.TrimStart();
if (s.Length > 0 && s[0] == '^')
{
Errors.Clear();
expr_without_brackets = expr_without_brackets.TrimStart().Substring(1);
tree = parser.GetExpression("test" + Path.GetExtension(FileName), s.Substring(1), Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
exprWithoutBrackets = exprWithoutBrackets.TrimStart().Substring(1);
expressionTree = parser.GetExpression("test" + Path.GetExtension(fileName), s.Substring(1), Errors, Warnings);
}
}
}
if (tree == null || Errors.Count > 0)
List<PascalABCCompiler.Errors.Error> Errors2 = new List<PascalABCCompiler.Errors.Error>();
// проверка для выражения без скобок
PascalABCCompiler.SyntaxTree.expression expressionTree2 = parser.GetExpression("test" + Path.GetExtension(fileName), exprWithoutBrackets, Errors2, Warnings);
// если не получается, то сразу возврат
if (expressionTree2 == null || Errors2.Count > 0)
return null;
bool header = false;
if (expressionTree == null || Errors.Count > 0)
{
Errors.Clear();
tree = parser.GetExpression("test" + Path.GetExtension(FileName), expr_without_brackets, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
header = true;
if (tree == null || Errors.Count > 0)
return null;
expressionTree = expressionTree2;
}
else
{
Errors.Clear();
PascalABCCompiler.SyntaxTree.expression tree2 = parser.GetExpression("test" + Path.GetExtension(FileName), expr_without_brackets, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
//header = true;
if (tree2 == null || Errors.Count > 0)
return null;
//if (tree is PascalABCCompiler.SyntaxTree.new_expr && (tree as PascalABCCompiler.SyntaxTree.new_expr).params_list == null)
// tree = tree2;
}
CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[FileName];
if (dconv == null) return null;
return dconv.GetDescription(tree, FileName, expr_without_brackets, e.LogicalPosition.Line, e.LogicalPosition.Column, keyw, header);
CodeCompletion.DomConverter domConverter = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName];
if (domConverter == null) return null;
return domConverter.GetDescription(expressionTree, fileName, exprWithoutBrackets, e.LogicalPosition.Line, e.LogicalPosition.Column, keyw, header);
}
static int _mouse_hint_x = 0, _mouse_hint_y = 0;

View file

@ -118,22 +118,38 @@ namespace VisualPascalABC
public static List<Position> GetDefinitionPosition(TextArea textArea, bool only_check)
{
if (CodeCompletion.CodeCompletionController.CurrentParser == null) return new List<Position>();
IParser parser = CodeCompletion.CodeCompletionController.CurrentParser;
if (parser == null)
return new List<Position>();
IDocument doc = textArea.Document;
string textContent = doc.TextContent;
ccp = new CodeCompletionProvider();
string full_expr;
string expressionResult = FindFullExpression(textContent, textArea, out ccp.keyword, out full_expr);
if (expressionResult != null)
expressionResult = expressionResult.Trim();
// Проверка, что компилируем Паскаль временно EVA 10.11.2024
if (parser == Languages.Facade.LanguageProvider.Instance.SelectLanguageByName(StringConstants.pascalLanguageName).Parser)
{
if (expressionResult != full_expr && full_expr.StartsWith("("))
return new List<Position>();
if (full_expr != null && full_expr.Contains("^"))
full_expr = full_expr.Replace("^","");
{
full_expr = full_expr.Replace("^", "");
}
}
List<Position> poses = ccp.GetDefinition(full_expr, textArea.MotherTextEditorControl.FileName, textArea.Caret.Line, textArea.Caret.Column, only_check);
if (poses == null || poses.Count == 0)
poses = ccp.GetDefinition(expressionResult, textArea.MotherTextEditorControl.FileName, textArea.Caret.Line, textArea.Caret.Column, only_check);
return poses;
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// 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 System;
using System.Collections;
@ -199,8 +199,10 @@ namespace VisualPascalABC
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsDefinitionIdentifierAfterKeyword(keyw))
return false;
// если не первый символ выражения (предыдущий тоже буква или "_"), то не открываем новое окно
if (editor.ActiveTextAreaControl.TextArea.Caret.Offset > 0 && (char.IsLetterOrDigit(editor.Document.TextContent[editor.ActiveTextAreaControl.TextArea.Caret.Offset - 1]) || editor.Document.TextContent[editor.ActiveTextAreaControl.TextArea.Caret.Offset - 1] == '_'))
return false;
completionDataProvider = new CodeCompletionProvider();
codeCompletionWindow = PABCNETCodeCompletionWindow.ShowCompletionWindowWithFirstChar(
VisualPABCSingleton.MainForm, // The parent window for the completion window

View file

@ -1,8 +1,9 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// 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 System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
@ -113,12 +114,6 @@ namespace VisualPascalABC
if (VisualPABCSingleton.MainForm.VisualEnvironmentCompiler.compilerLoaded)
e = language.Parser.GetExpression("test" + System.IO.Path.GetExtension(fileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
if (e is PascalABCCompiler.SyntaxTree.bin_expr && expr.Contains("<"))
{
expr = expr.Replace("<","&<");
Errors.Clear();
e = language.Parser.GetExpression("test" + System.IO.Path.GetExtension(fileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
}
if (e == null)
return loc;
CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName];
@ -321,11 +316,118 @@ namespace VisualPascalABC
return expr;
}
public ICompletionData[] GetCompletionDataByFirst(int off, string Text, int line, int col, char charTyped, PascalABCCompiler.Parsers.KeywordKind keyw)
/// <summary>
/// Возвращает подсказки определяемые первым символом выражения, введенного пользователем
/// </summary>
public ICompletionData[] GetCompletionDataByFirst(int line, int col, char charTyped, KeywordKind keyw)
{
List<ICompletionData> resultList = new List<ICompletionData>();
List<ICompletionData> lst = new List<ICompletionData>();
try
{
ILanguageInformation languageInformation = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation;
List<string> keywords;
bool isTypeAfterKeyword = false;
// если по смыслу должен вводиться тип данных
if (languageInformation.IsTypeAfterKeyword(keyw))
{
keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetTypeKeywords();
isTypeAfterKeyword = true;
}
else
{
keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
}
bool isNamespaceAfterKeyword = false;
// конструкция типа "uses"
if (languageInformation.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)
{
bool languageCaseSensitive = LanguageProvider.Instance.SelectLanguageByExtension(FileName).CaseSensitive;
AddCompletionDatasByFirstForSymInfos(resultList, charTyped, symInfos, languageCaseSensitive);
//resultList.Sort();
//defaultCompletionElement = resultList[0] as DefaultCompletionData;
}
}
catch (Exception) { }
this.ByFirstChar = true;
return resultList.ToArray();
}
/// <summary>
/// Добавляет в resultList (итоговый список подсказок) данные, соответствующие переданному массиву типа SymInfo[].
/// Используется для случая ввода пользователем первого символа выражения
/// </summary>
private void AddCompletionDatasByFirstForSymInfos(List<ICompletionData> resultList, char charTyped, SymInfo[] symInfos, bool languageCaseSensitive)
{
HashSet<string> symbolsAdded = languageCaseSensitive ? new HashSet<string>() : new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
List<ICompletionData> candidatesForDefault = new List<ICompletionData>();
bool stop = false;
ICompletionData lastUsedItem = CompletionDataDispatcher.GetLastUsedItem(charTyped);
foreach (SymInfo symInfo in symInfos)
{
if (symInfo == null || symInfo.not_include) continue;
if (symbolsAdded.Contains(symInfo.name))
continue;
UserDefaultCompletionData completionData = new UserDefaultCompletionData(symInfo.name, symInfo.description, ImagesProvider.GetPictureNum(symInfo), false);
StringComparison stringComparison = languageCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
// если мы выбирали что-то раньше из списка подсказок, то считаем это элементом по умолчанию
if (!stop && lastUsedItem != null && string.Equals(symInfo.name, lastUsedItem.Text, stringComparison))
{
defaultCompletionElement = completionData;
stop = true;
}
// иначе формируем список подходящих подсказок - "кандидатов" для элемента по умолчанию
else if (!stop && lastUsedItem == null && symInfo.name.StartsWith(charTyped.ToString(), stringComparison))
{
//defaultCompletionElement = ddd;
candidatesForDefault.Add(completionData);
//stop = true;
}
disp.Add(symInfo, completionData);
resultList.Add(completionData);
symbolsAdded.Add(symInfo.name);
}
if (candidatesForDefault.Count > 0)
defaultCompletionElement = candidatesForDefault.Min() as UserDefaultCompletionData; // здесь выбирается минимальное по длине
}
/// <summary>
/// Формирует массив данных из таблицы символов для подсказок в случае введения пользователем первой буквы выражения
/// </summary>
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
@ -334,238 +436,292 @@ namespace VisualPascalABC
dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[CodeCompletion.CodeCompletionNameHelper.system_unit_file_full_name];
special_module = true;
}*/
string pattern = charTyped.ToString();
string[] keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsTypeAfterKeyword(keyw))
SymInfo[] symInfos = null;
if (dconv == null)
{
keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetTypeKeywords();
}
if (!CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsNamespaceAfterKeyword(keyw))
foreach (string key in keywords)
if (isNamespaceAfterKeyword)
{
//if (key.StartsWith(pattern, StringComparison.CurrentCultureIgnoreCase))
resultList.Add(new UserDefaultCompletionData(key, null, ImagesProvider.IconNumberKeyword, false));
symInfos = CodeCompletion.DomConverter.standard_units;
}
PascalABCCompiler.Parsers.SymInfo[] mis = null;
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsNamespaceAfterKeyword(keyw))
{
mis = CodeCompletion.DomConverter.standard_units;
}
if (dconv != null)
else
{
//if (keyw == PascalABCCompiler.Parsers.KeywordKind.Colon || keyw == PascalABCCompiler.Parsers.KeywordKind.Of || keyw == PascalABCCompiler.Parsers.KeywordKind.TypeDecl)
if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsTypeAfterKeyword(keyw))
mis = dconv.GetTypeByPattern(pattern, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
else if (CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.IsNamespaceAfterKeyword(keyw) && mis == null)
mis = dconv.GetNamespaces();
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
mis = dconv.GetNameByPattern(null, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
symInfos = CodeCompletion.DomConverter.standard_units;
}
Hashtable cache = new Hashtable();
if (mis != null)
else
{
bool stop = false;
ICompletionData data = CompletionDataDispatcher.GetLastUsedItem(charTyped);
foreach (PascalABCCompiler.Parsers.SymInfo mi in mis)
{
if (mi.not_include) continue;
if (cache.Contains(mi.name))
continue;
UserDefaultCompletionData ddd = new UserDefaultCompletionData(mi.name, mi.description, ImagesProvider.GetPictureNum(mi), false);
if (!stop && data != null && string.Compare(mi.name, data.Text, true) == 0)
{
defaultCompletionElement = ddd;
stop = true;
// интересно, что передается pattern = null EVA
symInfos = dconv.GetNameByPattern(null, line, col, true, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
}
else if (!stop && data == null && mi.name.StartsWith(charTyped.ToString(), StringComparison.CurrentCultureIgnoreCase))
{
//defaultCompletionElement = ddd;
lst.Add(ddd);
//stop = true;
}
disp.Add(mi, ddd);
resultList.Add(ddd);
cache[mi.name] = mi;
}
//resultList.Sort();
//defaultCompletionElement = resultList[0] as DefaultCompletionData;
}
}
catch (Exception e)
{
}
lst.Sort();
if (lst.Count > 0) defaultCompletionElement = lst[0] as UserDefaultCompletionData;
ICompletionData[] res_arr = resultList.ToArray();
this.ByFirstChar = true;
return res_arr;
return symInfos;
}
public ICompletionData[] GetCompletionData(int off, string Text, int line, int col, char charTyped, PascalABCCompiler.Parsers.KeywordKind keyw)
/// <summary>
/// Вспомогательная струтура для метода GetCompletionData, хранит информацию о действиях пользователя
/// </summary>
private struct ActionContext
{
public bool dotPressed;
public bool ctrlSpace;
public bool shiftSpace;
public bool spaceAfterNew;
public bool spaceAfterUses;
}
/// <summary>
/// Возвращает массив подсказок для случая нажатия пользователем "триггерной" клавиши
/// </summary>
public ICompletionData[] GetCompletionData(int off, string text, int line, int col, char charTyped, KeywordKind keywordKind)
{
List<ICompletionData> resultList = new List<ICompletionData>();
try
{
string pattern = null;
string expr = null;
bool ctrl_space = charTyped == '\0' || charTyped == '_';
bool shift_space = charTyped == '\0';
bool inside_dot_pattern = false;
bool new_space = keyw == PascalABCCompiler.Parsers.KeywordKind.New;
if (ctrl_space)
// поменять на обращение к CodeCompletionController.CurrentLanguage
ILanguage currentLanguage = LanguageProvider.Instance.SelectLanguageByExtension(FileName);
var context = new ActionContext()
{
bool is_pattern = false;
pattern = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.FindPattern(off, Text, out is_pattern);
if (is_pattern && Text[off - pattern.Length - 1] == '.')
dotPressed = charTyped == '.',
ctrlSpace = charTyped == '_',
shiftSpace = charTyped == '\0',
spaceAfterNew = keywordKind == KeywordKind.New,
spaceAfterUses = keywordKind == KeywordKind.Uses
};
string expressionText = GetExpressionTextForCompletionData(off, text, line, col,
currentLanguage.LanguageInformation, in context, out var insidePatternWithDots, out var ctrlOrShiftSpaceAfterDot, out var pattern);
// добавляем ключевые слова в случае "ctrl + space", нажатых в "пустом" месте
if (!ctrlOrShiftSpaceAfterDot && context.ctrlSpace && string.IsNullOrEmpty(pattern))
{
inside_dot_pattern = true;
expr = FindExpression(off - pattern.Length - 1, Text, line, col);
var keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
resultList.AddRange(keywords.Select(keyword =>
new UserDefaultCompletionData(keyword, null, ImagesProvider.IconNumberKeyword, false)));
}
}
else if (new_space)
PascalABCCompiler.SyntaxTree.expression expr = null;
// для "ctrl + space" и "shift + space" дерево expression не требуется (кроме случая insidePatternWithDots)
if ((context.dotPressed || context.spaceAfterNew || context.spaceAfterUses || insidePatternWithDots) && expressionText != null)
{
expr = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.SkipNew(off - 1, Text, ref keyword);
}
else
if (!new_space && keyw != PascalABCCompiler.Parsers.KeywordKind.Uses)
if (charTyped != '$')
expr = FindExpression(off, Text, line, col);
else
expr = FindExpression(off - 1, Text, line, col);
List<PascalABCCompiler.Errors.Error> Errors = new List<PascalABCCompiler.Errors.Error>();
PascalABCCompiler.SyntaxTree.expression e = null;
if (ctrl_space && !shift_space && (pattern == null || pattern == ""))
{
string[] keywords = CodeCompletion.CodeCompletionNameHelper.Helper.GetKeywords();
foreach (string key in keywords)
{
//if (key.StartsWith(pattern, StringComparison.CurrentCultureIgnoreCase))
resultList.Add(new UserDefaultCompletionData(key, null, ImagesProvider.IconNumberKeyword, false));
}
expr = GetExpressionForCompletionData(currentLanguage.Parser,
in context, expressionText, insidePatternWithDots, out var shouldReturnNull);
if (shouldReturnNull)
return null;
}
ILanguage currentLanguage = LanguageProvider.Instance.SelectLanguageByExtensionSafe(FileName);
SymInfo[] symInfos = GetSymInfosForCompletionData(line, col, in context, currentLanguage.CaseSensitive,
expressionText, ctrlOrShiftSpaceAfterDot, insidePatternWithDots, pattern, expr, out var selectedSymInfo, out var lastUsedMember, out var shouldReturnNull2);
if (currentLanguage == null)
if (shouldReturnNull2)
return null;
if ((!ctrl_space || inside_dot_pattern) && expr != null)
if (symInfos != null)
{
e = currentLanguage.Parser.GetTypeAsExpression("test" + System.IO.Path.GetExtension(FileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
if (e == null)
{
Errors.Clear();
e = currentLanguage.Parser.GetExpression("test" + System.IO.Path.GetExtension(FileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
AddCompletionDatasForSymInfos(resultList, currentLanguage.CaseSensitive, symInfos, selectedSymInfo, lastUsedMember);
}
if ((e == null || Errors.Count > 0) && !new_space) return null;
}
SymInfo[] mis = null;
CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[FileName];
if (dconv == null)
{
if (keyw == PascalABCCompiler.Parsers.KeywordKind.Uses)
mis = CodeCompletion.DomConverter.standard_units;
else if (!ctrl_space)
return new ICompletionData[0];
}
string fname = FileName;
SymInfo sel_si = null;
string last_used_member = null;
if (dconv != null)
{
if (new_space)
mis = dconv.GetTypes(e, line, col, out sel_si);
else if (keyw == PascalABCCompiler.Parsers.KeywordKind.Uses && mis == null)
{
if (WorkbenchServiceFactory.Workbench.UserOptions.EnableSmartIntellisense)
mis = dconv.GetNamespaces();
else
mis = CodeCompletion.DomConverter.standard_units;
catch (Exception) { }
return resultList.ToArray();
}
else
if (!ctrl_space)
/// <summary>
/// Добавляет в resultList (итоговый список подсказок) данные, соответствующие переданному массиву типа SymInfo[].
/// Используется для случая нажатия пользователем "триггерной" клавиши
/// </summary>
private void AddCompletionDatasForSymInfos(List<ICompletionData> resultList, bool languageCaseSensitive, SymInfo[] symInfos, SymInfo selectedSymInfo, string lastUsedMember)
{
CodeCompletion.SymScope dot_sc = null;
mis = dconv.GetName(e, expr, line, col, keyword, ref dot_sc);
if (dot_sc != null && VisualPABCSingleton.MainForm.UserOptions.EnableSmartIntellisense)
{
CompletionDataDispatcher.AddMemberBeforeDot(dot_sc);
last_used_member = CompletionDataDispatcher.GetRecentUsedMember(dot_sc);
}
}
else
{
CodeCompletion.SymScope dot_sc = null;
if (inside_dot_pattern)
{
List<SymInfo> si_list = new List<SymInfo>();
SymInfo[] from_list = dconv.GetName(e, expr, line, col, keyword, ref dot_sc);
for (int i = 0; i < from_list.Length; i++)
{
if (from_list[i].name.StartsWith(pattern, StringComparison.OrdinalIgnoreCase))
si_list.Add(from_list[i]);
}
mis = si_list.ToArray();
}
// ICompletionData data = null;
else
mis = dconv.GetNameByPattern(pattern, line, col, charTyped == '_', VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
}
HashSet<string> symbolsAdded = languageCaseSensitive ? new HashSet<string>() : new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
}
Hashtable cache = null;
if (!currentLanguage.CaseSensitive)
cache = new Hashtable(StringComparer.CurrentCultureIgnoreCase);
else
cache = new Hashtable();
int num = 0;
if (mis != null)
foreach (SymInfo symInfo in symInfos)
{
bool stop = false;
ICompletionData data = null;
foreach (SymInfo mi in mis)
{
if (mi.not_include) continue;
if (cache.Contains(mi.name + mi.kind))
if (symInfo == null || symInfo.not_include)
continue;
UserDefaultCompletionData ddd = new UserDefaultCompletionData(mi.addit_name != null ? mi.addit_name : mi.name, mi.description, ImagesProvider.GetPictureNum(mi), false);
if (symbolsAdded.Contains(symInfo.name + symInfo.kind))
continue;
UserDefaultCompletionData completionData = new UserDefaultCompletionData(
symInfo.addit_name != null ? symInfo.addit_name : symInfo.name,
symInfo.description, ImagesProvider.GetPictureNum(symInfo), false
);
disp.Add(symInfo, completionData);
resultList.Add(completionData);
symbolsAdded.Add(symInfo.name + symInfo.kind);
disp.Add(mi, ddd);
resultList.Add(ddd);
cache[mi.name + mi.kind] = mi;
/*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 (last_used_member != null && last_used_member == mi.name)
if (lastUsedMember != null && lastUsedMember == symInfo.name || selectedSymInfo != null && symInfo == selectedSymInfo)
{
defaultCompletionElement = ddd;
}
if (sel_si != null && mi == sel_si)
{
defaultCompletionElement = ddd;
stop = true;
defaultCompletionElement = completionData;
}
}
if (defaultCompletionElement == null && data != null)
defaultCompletionElement = data as UserDefaultCompletionData;
/*if (defaultCompletionElement == null && data != null)
defaultCompletionElement = data as UserDefaultCompletionData;*/
}
/// <summary>
/// Формирует массив данных из таблицы символов для подсказок в случае нажатия пользователем "триггерной" клавиши
/// (в зависимости от введенного выражения и другого контекста)
/// </summary>
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);
}
}
catch (Exception e)
// ctrl + space после некоторого выражения
else if (context.ctrlSpace) // context.chiftSpace здесь не может быть true, поскольку такие ситуации обрабатываются в ShiftSpaceActions.Execute()
{
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();
}
return resultList.ToArray();
else
symInfos = dconv.GetNameByPattern(pattern, line, col, context.ctrlSpace, VisualPABCSingleton.MainForm.UserOptions.CodeCompletionNamespaceVisibleRange);
}
}
return symInfos;
}
/// <summary>
/// Возвращает дерево выражения, введенного пользователем перед нажатием "триггерной" клавиши
/// </summary>
private PascalABCCompiler.SyntaxTree.expression GetExpressionForCompletionData(IParser parser, in ActionContext context, string expressionText, bool insidePatternWithDots, out bool shouldReturnNull)
{
shouldReturnNull = false;
List<PascalABCCompiler.Errors.Error> Errors = new List<PascalABCCompiler.Errors.Error>();
List<PascalABCCompiler.Errors.CompilerWarning> Warnings = new List<PascalABCCompiler.Errors.CompilerWarning>();
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;
}
/// <summary>
/// Получение текста выражения, введенного пользователем перед нажатием "триггерной" клавиши
/// </summary>
private string GetExpressionTextForCompletionData(int off, string text, int line, int col, ILanguageInformation languageInformation, 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 = languageInformation.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 = languageInformation.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;
@ -640,7 +796,7 @@ namespace VisualPascalABC
string text = textArea.Document.TextContent.Substring(0, textArea.Caret.Offset);
//controller.Compile(file_name, text /*+ ")))));end."*/);
FileName = fileName; Text = text;
ICompletionData[] data = GetCompletionDataByFirst(off, text, textArea.Caret.Line, textArea.Caret.Column, charTyped, keyw);
ICompletionData[] data = GetCompletionDataByFirst(textArea.Caret.Line, textArea.Caret.Column, charTyped, keyw);
CodeCompletion.AssemblyDocCache.CompleteDocumentation();
CodeCompletion.UnitDocCache.CompleteDocumentation();
controller = null;

View file

@ -18,65 +18,68 @@ namespace VisualPascalABC
private static string GetPopupHintText(TextArea textArea, ToolTipRequestEventArgs e)
{
ICSharpCode.TextEditor.TextLocation logicPos = e.LogicalPosition;
TextLocation logicPos = e.LogicalPosition;
IDocument doc = textArea.Document;
LineSegment seg = doc.GetLineSegment(logicPos.Y);
string FileName = textArea.MotherTextEditorControl.FileName;
PascalABCCompiler.Parsers.KeywordKind keyw = PascalABCCompiler.Parsers.KeywordKind.None;
if (logicPos.X > seg.Length - 1)
LineSegment lineSegment = doc.GetLineSegment(logicPos.Y);
string fileName = textArea.MotherTextEditorControl.FileName;
if (logicPos.X > lineSegment.Length - 1)
return null;
//string expr = FindFullExpression(doc.TextContent, seg.Offset + logicPos.X,e.LogicalPosition.Line,e.LogicalPosition.Column);
string expr_without_brackets = null;
string expr = CodeCompletion.CodeCompletionController.CurrentParser.LanguageInformation.FindExpressionFromAnyPosition(seg.Offset + logicPos.X, doc.TextContent, e.LogicalPosition.Line, e.LogicalPosition.Column, out keyw, out expr_without_brackets);
IParser parser = CodeCompletion.CodeCompletionController.CurrentParser;
string expr = parser.LanguageInformation.FindExpressionFromAnyPosition(
lineSegment.Offset + logicPos.X, doc.TextContent, e.LogicalPosition.Line, e.LogicalPosition.Column, out var keyw, out var exprWithoutBrackets);
// пока непонятно, когда такое может быть EVA
if (expr == null)
expr = exprWithoutBrackets;
if (expr == null)
expr = expr_without_brackets;
if (expr_without_brackets == null)
return null;
List<PascalABCCompiler.Errors.Error> Errors = new List<PascalABCCompiler.Errors.Error>();
List<PascalABCCompiler.Errors.CompilerWarning> Warnings = new List<PascalABCCompiler.Errors.CompilerWarning>();
IParser parser = Languages.Facade.LanguageProvider.Instance.SelectLanguageByExtension(FileName).Parser;
PascalABCCompiler.SyntaxTree.expression expressionTree = parser.GetExpression("test" + Path.GetExtension(fileName),
expr, Errors, Warnings);
PascalABCCompiler.SyntaxTree.expression tree = parser.GetExpression("test" + Path.GetExtension(FileName), expr, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
bool header = false;
if (Errors.Count > 0)
{
if (expr.IndexOf('<') != -1 && expr.IndexOf('>') != -1)
{
Errors.Clear();
tree = parser.GetExpression("test" + Path.GetExtension(FileName), expr.Replace("<", "&<"), Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
}
else
// Пока добавили проверку, что анализируем Паскаль EVA
if (Errors.Count > 0 && parser == Languages.Facade.LanguageProvider.Instance.SelectLanguageByName(PascalABCCompiler.StringConstants.pascalLanguageName).Parser)
{
string s = expr.TrimStart();
if (s.Length > 0 && s[0] == '^')
{
Errors.Clear();
expr_without_brackets = expr_without_brackets.TrimStart().Substring(1);
tree = parser.GetExpression("test" + Path.GetExtension(FileName), s.Substring(1), Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
exprWithoutBrackets = exprWithoutBrackets.TrimStart().Substring(1);
expressionTree = parser.GetExpression("test" + Path.GetExtension(fileName), s.Substring(1), Errors, Warnings);
}
}
}
if (tree == null || Errors.Count > 0)
List<PascalABCCompiler.Errors.Error> Errors2 = new List<PascalABCCompiler.Errors.Error>();
// проверка для выражения без скобок
PascalABCCompiler.SyntaxTree.expression expressionTree2 = parser.GetExpression("test" + Path.GetExtension(fileName), exprWithoutBrackets, Errors2, Warnings);
// если не получается, то сразу возврат
if (expressionTree2 == null || Errors2.Count > 0)
return null;
bool header = false;
if (expressionTree == null || Errors.Count > 0)
{
Errors.Clear();
tree = parser.GetExpression("test" + Path.GetExtension(FileName), expr_without_brackets, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
header = true;
if (tree == null || Errors.Count > 0)
return null;
expressionTree = expressionTree2;
}
else
{
Errors.Clear();
PascalABCCompiler.SyntaxTree.expression tree2 = parser.GetExpression("test" + Path.GetExtension(FileName), expr_without_brackets, Errors, new List<PascalABCCompiler.Errors.CompilerWarning>());
//header = true;
if (tree2 == null || Errors.Count > 0)
return null;
//if (tree is PascalABCCompiler.SyntaxTree.new_expr && (tree as PascalABCCompiler.SyntaxTree.new_expr).params_list == null)
// tree = tree2;
}
CodeCompletion.DomConverter dconv = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[FileName];
if (dconv == null) return null;
return dconv.GetDescription(tree, FileName, expr_without_brackets, e.LogicalPosition.Line, e.LogicalPosition.Column, keyw, header);
CodeCompletion.DomConverter domConverter = (CodeCompletion.DomConverter)CodeCompletion.CodeCompletionController.comp_modules[fileName];
if (domConverter == null) return null;
return domConverter.GetDescription(expressionTree, fileName, exprWithoutBrackets, e.LogicalPosition.Line, e.LogicalPosition.Column, keyw, header);
}
static int _mouse_hint_x = 0, _mouse_hint_y = 0;

View file

@ -1,41 +1,56 @@
#### Подсказка при наведении мыши
На верхнем уровне реализуется в классе `TooltipServiceManager`. Основная логика реализована в методе `GetPopupHintText`. Вначале вызывается `FindExpressionFromAnyPosition` для получения нужного `expression` в виде строки.
Затем вызывается нужный парсер для получения дерева выражения (используется часть грамматики, связанная с нетерминалом parts). Если не получается распарсить, то делается попытка с решением неоднозначности, связанной с шаблонными параметрами (&<).
После этого еще попытка с удалением разыменования, пока непонятно зачем это.
Еще удаление разыменования было найдено в методе `GetDefinitionPosition` из `CodeCompletionActions`.
Затем еще попытка с тем же выражением без скобочек. При этом, если без скобочек распарсить не удается, то вне зависимости от успешности парсинга полного `expression` возвращается `null`.
Затем вызывается нужный парсер для получения дерева выражения (используется часть грамматики, связанная с нетерминалом parts). Если не получается распарсить, то делается попытка с удалением символа разыменования в выражении, пока неясно в какой ситуации это требуется.
Еще удаление разыменования присутствует в методе `GetDefinitionPosition` из `CodeCompletionActions`.
Затем делается еще попытка с тем же выражением без скобочек. При этом, если без скобочек распарсить не удается, то вне зависимости от успешности парсинга полного `expression` возвращается `null`.
В конце проверяется был ли успешен обход дерева программы визитором (`DomSyntaxTreeVisitor`). Если это так, то в словаре откомпилированных модулей будет данный модуль и соответствующий ему `DomConverter`.
Тогда мы сможем вызвать метод `GetDescription` из этого класса, который выдаст нам описание выражения.
Тогда есть возможность вызвать метод `GetDescription` из этого класса, который выдаст нам описание выражения.
#### Подсказка параметров функции
На нажатие клавиш (скобки, квадратной скобки или запятой) реагирует `TextAreaKeyEventHandler` из класса `CodeCompletionKeyHandler`. Там создается экземпляр `DefaultInsightDataProvider`, который загружается в стек провайдеров. Информация для подсказки формируется в методе `SetupDataProvider` инсайт-провайдера. После выяснения кода на текущей подстроке вызывается `FindExpressionForMethod` из `LanguageInformation`.
Далее делается попытка парсинга стандартным парсером языка и наконец из `DomConverter` вызывается `GetNameOfMethod`, либо `GetIndex` в зависимости от нажатой клавиши.
#### Подсказка по нажатию клавиш (по точке или пробелу)
#### Подсказка по нажатию клавиш
`CodeCompletionKeyHandler` реагирует на нажатие вызовом метода `ShowCompletionWindow`. В нем есть обращение к `GenerateCompletionDataWithKeyword` из класса `CodeCompletionProvider`. В этом методе выделяется нужная подстрока и есть обращение к методу `GetCompletionData`.
**Логика этого метода следующая:**
1) если был нажат `ctrl + space` (`shift + space` входит в это понятие тоже)
Вызывается `FindPattern` из `LanguageInformation` для получения "токена" до каретки. Если в процессе встретится точка, то вызывается `FindExpression`. Ниже если pattern пустой, то в итоговый список `ICompletionData` добавляются ключевые слова языка.
Вначале выясняется контекст вызова Intellisense, а именно нажатые пользователем клавиши и т. п. Далее вызывается специальный метод для получения текста выражения, введенного пользователем. При этом
1) если был нажат `ctrl + space` или `shift + space`
Вызывается `FindPattern` из `LanguageInformation` для получения "токена" до курсора. Если в процессе встретится точка, то вызывается `FindExpression`.
2) если был нажат пробел после `new`
Вызывается SkipNew для пропуска `new` и поиска expression перед ним.
3) иначе, если не было введено `uses`
3) иначе, если пользователем была введена точка
вызывается `FindExpression` (c текущей позиции)
Далее, если [**не** `ctrl + space` или была найдена цепочка имен в выражении] и выражение не пусто, то делается попытка вызова функции `GetTypeAsExpression` стандартного парсера. Если это ничего не дало далее попытка вызова `GetExpression`. Если снова ничего не удалось и мы не в случае пробела после `new`, то возврат.
Ниже если был нажат `ctrl + space` не после точки и pattern пустой то в итоговый список `ICompletionData` добавляются ключевые слова языка.
Далее, если Intellisense успешно не обошла текущий модуль, то для случая `uses` мы будем рассматривать SymInfo стандартных модулей (взятых из DomConverter). Если же у нас не `uses`случай и не случай ctrl + space, мы возвращаем пустой массив.
Далее, если выражение не пусто, то строится дерево требуемого expression (это не требуется для `ctrl + space` и `shift + space`, кроме случая, когда они нажаты в цепочечном выражении с точками). Внутри метода построения дерева делается попытка вызова функции `GetTypeAsExpression`, а затем `GetExpression`. Если ничего не удалось построить и мы не в случае пробела после `new`, то нужно выходить из внешнего метода `GetCompletionData`.
Далее получаем необходимую информацию о выражениях для нужного expression из таблицы символов (в специальном методе). Если визитор Intellisense успешно не обошел текущий модуль (тогда мы не получим соотв. экземпляр `DomConverter`), то
- Если у нас не случай `ctrl + space` или `shift + space` , нужно вернуть пустой массив `ICompletionData`.
- Для случая `uses` сразу добавляем массив стандартных модулей языка
Иначе, если у нас есть `DomConverter`:
- Если пробел после `new`, то вызываем `GetTypes`
- Иначе, если `uses`, то работаем со списком стандартных модулей + пр-в имен в случае семантического Intellisense.
- Иначе, если не `ctrl + space` (случай, когда мы поставили точку), то вызываем `GetName` для получения всех возможных имен после точки
- Иначе, если `ctrl + space`, то либо ищем имена после точки - `GetName` (если точка была раньше), либо ищем имя по его началу - `GetNameByPattern`
- Иначе, если была нажата точка, либо `ctrl + space` или `shift + space` сразу после точки, то вызываем `GetName` для получения всех возможных имен после точки
- Иначе, если `ctrl + space`, то либо ищем имена, подходящие для помещения после точки, начинающиеся на `pattern` - `GetName` + `StartsWith`, либо просто ищем имя по его началу - `GetNameByPattern`
> [!NOTE] Замечание
>Также на нажатие реагирует Execute из CodeCompletionAllNamesAction. key подменяется на доллар если это было нажатие `ctrl + space` сразу после точки.
В конце по полученным SymInfo строится результирующий список CompletionData (без повторений).
> [!NOTE] Замечание
>Случаи обработки `ctrl + space` и `shift + space` перед вызовом `GetCompletionData` обрабатываются не в классе `CodeCompletionKeyHandler`, а в отдельных классах файла CodeCompletionActions. У `ctrl + space` класс называется `CodeCompletionAllNamesAction`, а у `shift + space` - `CodeCompletionShiftSpaceActions`. При этом для `shift + space` в вышеупомянутом классе предварительно проверяются еще два сценария его применения помимо подсказки локальных имен, реализованной в `GetCompletionData`. Эти сценарии - это автодополнение xml-комментария и автодополнение выражений из файла template.pct языка.
#### Подсказка по первому символу выражения
Данная ситуация обрабатывается в последней ветке метода `TextAreaKeyEventHandler` класса `CodeCompletionKeyHandler`. Оттуда цепочка вызовов приходит к методу `GetCompletionDataByFirst`. В этом методе мы так же как в `GetCompletionData` вначале выясняем контекст, а именно должен ли в данной позиции быть введен тип данных, либо мы находимся в секции "uses". Если мы не в "uses", то можно добавить в результирующий список подсказок нужные ключевые слова.
Далее получаем нужную информацию из таблицы символов в специальном методе по следующим правилам:
Если `DomConverter` данного модуля получить невозможно, то в случае "uses" можно добавить список стандартных модулей.
Если же `DomConverter` получен, то
- если нужно подсказать типы данных вызывается `GetTypeByPattern`
- если секция "uses", то либо вызывается `GetNamespaces` когда включен семантический Intellisense, либо просто добавляется список стандартных модулей
- во всех остальных ситуациях вызывается `GetNameByPattern`, причем ему передается пустой `pattern`
После этого в специальном методе по полученным SymInfo строим результирующий список подсказок без повторений. При этом назначается значение `defaultCompletionElement` (подсказки, которая выбирается по умолчанию). Это будет либо прошлый выбранный вариант подсказки, либо если такого не найдется, то минимальный элемент по длине.
#### Переход к определению символа
В `CodeCompletionActoins` есть специальный класс GotoAction, в котором вызывается метод `GoToDefinition`. В этом методе используется метод GetDefinitionPosition, который в свою очередь (тоже косвенно) использует `FindExpressionFromAnyPosition` из `LanguageInformation` и `GetDefinition` из `CodeCompletionProvider`. Последний вышеупомянутый метод является оберткой на `GetDefinition` из DomConverter.
В `CodeCompletionActions` есть специальный класс `GotoAction`, в котором вызывается метод `GoToDefinition`. В этом методе используется метод `GetDefinitionPosition`, который в свою очередь (тоже косвенно) использует `FindExpressionFromAnyPosition` из `LanguageInformation` и `GetDefinition` из `CodeCompletionProvider`. Последний вышеупомянутый метод является оберткой над `GetDefinition` из `DomConverter`.