├── Screenshots
├── find-window.png
├── spans-sample.png
├── syntax-highlighting.png
└── current-line-highlihting.png
├── SA.CodeView
├── Coco
│ ├── Scanner.frame
│ └── Parser.frame
├── CodeViewer
│ ├── TextCaret.cs
│ ├── TextStyle.cs
│ ├── SmallTypes.cs
│ ├── TextFinder.cs
│ ├── TextPoint.cs
│ ├── Document.cs
│ ├── TextSpan.cs
│ ├── FindForm.resx
│ ├── CodeViewerBody.resx
│ └── FindForm.cs
├── Languages
│ ├── SyntaxSettings.cs
│ ├── Enums.cs
│ ├── NonSyntaxSettings.cs
│ ├── XmlSyntaxSettings.cs
│ ├── CSharpSyntaxSettings.cs
│ ├── VisualBasicSyntaxSettings.cs
│ └── MySqlSyntaxSettings.cs
├── IntelliSense
│ ├── Visual
│ │ ├── Icons
│ │ │ ├── db.bmp
│ │ │ ├── table.bmp
│ │ │ ├── column.bmp
│ │ │ └── schema.bmp
│ │ ├── IntellisenseMessageFilter.cs
│ │ ├── IntellisenseForm.Designer.cs
│ │ └── WinApi.cs
│ ├── DbInfoProvider
│ │ └── DbInfoProvider.cs
│ ├── WhereSuggestionBuilder.cs
│ ├── SuggestionBuilder.cs
│ └── CompletionVariant.cs
├── Parsing
│ ├── RuleDefParsing
│ │ ├── Grammar.atg
│ │ ├── coc.bat
│ │ └── Parser.HandMade.cs
│ ├── TokenDefParsing
│ │ ├── Grammar.atg
│ │ ├── coc.bat
│ │ └── Parser.HandMade.cs
│ ├── ParsingOnElements (obsolete)
│ │ ├── SyntaxParser.cs
│ │ ├── Enums.cs
│ │ ├── Sequence.cs
│ │ ├── BaseElement.cs
│ │ ├── FixedListElement.cs
│ │ ├── SingleElement.cs
│ │ └── BoundedElement.cs
│ ├── ISyntaxParser.cs
│ ├── Token.cs
│ ├── Literal.cs
│ ├── ParserSpecification.cs
│ ├── StateParserState.cs
│ ├── StateScannerState.cs
│ ├── BufferReader.cs
│ └── StateScanner.cs
├── AssemblyInfo.cs
├── Editing
│ ├── UndoRedoOperation.cs
│ ├── ClipboardProxyClass.cs
│ └── UndoRedoManager.cs
└── Utils
│ ├── TextSplitter.cs
│ └── WordFinder.cs
├── SA.CodeView.Tests
├── Parsing
│ ├── StateScannerTests.cs
│ ├── ParsingOnElements
│ │ └── ParserTests.cs
│ ├── SyntaxSettingsTests.cs
│ ├── NonSyntaxSettingsTests.cs
│ ├── StateParserTests.cs
│ ├── MsSqlParsingTests.cs
│ └── XmlParsingTests.cs
├── app.config
├── AssemblyInfo.cs
├── packages.config
├── Entry.cs
├── IntelliSense
│ ├── BasicTests.cs
│ ├── CodeViewerTokenIndexTests.cs
│ ├── BLL
│ │ └── TestDbInfoProvider.cs
│ ├── AutoCompleteTests.cs
│ └── CodeCompletorTests.cs
├── CodeViewing
│ ├── FontColorTests.cs
│ └── RendererTests.cs
├── TestForms
│ └── StartForm.resx
└── SampleData
│ └── SampleXml.xml
├── README.md
├── .gitignore
└── SA.CodeView.sln
/Screenshots/find-window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/Screenshots/find-window.png
--------------------------------------------------------------------------------
/SA.CodeView/Coco/Scanner.frame:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/Coco/Scanner.frame
--------------------------------------------------------------------------------
/Screenshots/spans-sample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/Screenshots/spans-sample.png
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/TextCaret.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/CodeViewer/TextCaret.cs
--------------------------------------------------------------------------------
/Screenshots/syntax-highlighting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/Screenshots/syntax-highlighting.png
--------------------------------------------------------------------------------
/SA.CodeView/Languages/SyntaxSettings.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/Languages/SyntaxSettings.cs
--------------------------------------------------------------------------------
/Screenshots/current-line-highlihting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/Screenshots/current-line-highlihting.png
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/Visual/Icons/db.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/IntelliSense/Visual/Icons/db.bmp
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Parsing/StateScannerTests.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView.Tests/Parsing/StateScannerTests.cs
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/Visual/Icons/table.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/IntelliSense/Visual/Icons/table.bmp
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/RuleDefParsing/Grammar.atg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/Parsing/RuleDefParsing/Grammar.atg
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/TokenDefParsing/Grammar.atg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/Parsing/TokenDefParsing/Grammar.atg
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/Visual/Icons/column.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/IntelliSense/Visual/Icons/column.bmp
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/Visual/Icons/schema.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/IntelliSense/Visual/Icons/schema.bmp
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Parsing/ParsingOnElements/ParserTests.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView.Tests/Parsing/ParsingOnElements/ParserTests.cs
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParsingOnElements (obsolete)/SyntaxParser.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ygavrishov/SA.CodeView/HEAD/SA.CodeView/Parsing/ParsingOnElements (obsolete)/SyntaxParser.cs
--------------------------------------------------------------------------------
/SA.CodeView.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ISyntaxParser.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SA.CodeView.Parsing
4 | {
5 | interface ISyntaxParser
6 | {
7 | List Parse(List lines);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParsingOnElements (obsolete)/Enums.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.ParsingOnElements
4 | {
5 | enum ElementContent
6 | {
7 | Specified,
8 | AnyToken,
9 | Id,
10 | };
11 | }
--------------------------------------------------------------------------------
/SA.CodeView/Languages/Enums.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView
4 | {
5 | public enum PredefinedLanguage
6 | {
7 | None,
8 | MsSql,
9 | Xml,
10 | MySql,
11 | Oracle,
12 | Access,
13 | CSharp,
14 | VisualBasic
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/RuleDefParsing/coc.bat:
--------------------------------------------------------------------------------
1 | @"..\..\Coco\Coco.exe" -frames "..\..\Coco" Grammar.atg -namespace SA.CodeView.Parsing.RuleDefParsing
2 | @IF %ERRORLEVEL% == 0 GOTO SUCCESS
3 | :SUCCESS
4 | :END
5 | @del Parser.cs.old
6 | @del Scanner.cs.old
7 | @pause
8 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/TokenDefParsing/coc.bat:
--------------------------------------------------------------------------------
1 | @"..\..\Coco\Coco.exe" -frames "..\..\Coco" Grammar.atg -namespace SA.CodeView.Parsing.TokenDefParsing
2 | @IF %ERRORLEVEL% == 0 GOTO SUCCESS
3 | :SUCCESS
4 | :END
5 | @del Parser.cs.old
6 | @del Scanner.cs.old
7 | @pause
8 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyVersion("2.0.34")]
6 |
7 | [assembly: ComVisible(false)]
8 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
--------------------------------------------------------------------------------
/SA.CodeView/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyProduct("SA.CodeView")]
6 |
7 | [assembly: AssemblyVersion("2.0.34")]
8 |
9 | [assembly: ComVisible(false)]
10 | [assembly: InternalsVisibleTo("SA.CodeView.Tests")]
11 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/DbInfoProvider/DbInfoProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SA.CodeView.IntelliSense
6 | {
7 | public interface IDbInfoProvider
8 | {
9 | List GetSchemas();
10 | List GetObjectsInSchema(string schema);
11 | List GetColumnsFor(string schema, string table);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Entry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 | using Tests.TestForms;
4 |
5 | namespace Tests
6 | {
7 | class Entry
8 | {
9 | //=========================================================================================
10 | [STAThread]
11 | public static void Main()
12 | {
13 | Application.EnableVisualStyles();
14 | Application.Run(new StartForm());
15 | }
16 | //=========================================================================================
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/RuleDefParsing/Parser.HandMade.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.Parsing.RuleDefParsing
4 | {
5 | partial class Parser
6 | {
7 | /// Спецификация работы сканера, для которой мы формируем граф переходов.
8 | public ParserSpecification Spec;
9 | //=========================================================================================
10 | public void Parse()
11 | {
12 | this._Parse();
13 | }
14 | //=========================================================================================
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/TokenDefParsing/Parser.HandMade.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.Parsing.TokenDefParsing
4 | {
5 | partial class Parser
6 | {
7 | /// Спецификация работы сканера, для которой мы формируем граф переходов.
8 | public ScannerSpecification Spec;
9 | //=========================================================================================
10 | public void Parse()
11 | {
12 | this._Parse();
13 | }
14 | //=========================================================================================
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParsingOnElements (obsolete)/Sequence.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.ParsingOnElements
5 | {
6 | class Sequence : BaseElement
7 | {
8 | public int MinOccurs = 1;
9 | public int MaxOccurs = 1;
10 | public readonly List Elements;
11 | //=========================================================================================
12 | public Sequence() : base(null)
13 | {
14 | this.Elements = new List();
15 | }
16 | //=========================================================================================
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/SA.CodeView/Editing/UndoRedoOperation.cs:
--------------------------------------------------------------------------------
1 | namespace SA.CodeView.Editing
2 | {
3 | internal enum UndoRedoOperationType
4 | {
5 | Insert,
6 | Remove,
7 | CaretReturn,
8 | Paste
9 | }
10 |
11 | internal class UndoRedoOperation
12 | {
13 | public UndoRedoOperationType Type;
14 | public int StartLine;
15 | public int StartChar;
16 | public int EndLine;
17 | public int EndChar;
18 | public string Text;
19 | public string PreviousText;
20 |
21 | public override string ToString() => $"{Type}, {nameof(StartLine)}={StartLine}, {nameof(StartChar)}={StartChar}, {nameof(EndLine)}={EndLine}, {nameof(EndChar)}={EndChar}";
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParsingOnElements (obsolete)/BaseElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.ParsingOnElements
4 | {
5 | /// Базовый класс для элементов, на которые нужно разбить входной текст.
6 | public abstract class BaseElement
7 | {
8 | /// Стиль отображения текста.
9 | public readonly TextStyle Style;
10 | //=========================================================================================
11 | public BaseElement(TextStyle style)
12 | {
13 | this.Style = style;
14 | }
15 | //=========================================================================================
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParsingOnElements (obsolete)/FixedListElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.ParsingOnElements
5 | {
6 | /// Фрагмент текста сопоставляется с элементом, если он совпадает с одним из ключевых слов элемента.
7 | class FixedListElement : BaseElement
8 | {
9 | /// Список ключевых слов.
10 | public List Keywords;
11 | //=========================================================================================
12 | public FixedListElement(TextStyle style)
13 | : base(style)
14 | {
15 | this.Keywords = new List();
16 | }
17 | //=========================================================================================
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParsingOnElements (obsolete)/SingleElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.ParsingOnElements
4 | {
5 | class SingleElement : BaseElement
6 | {
7 | public readonly string Text;
8 | ElementContent Content;
9 | //=========================================================================================
10 | public SingleElement(string text)
11 | : base(null)
12 | {
13 | this.Content = ElementContent.Specified;
14 | this.Text = text;
15 | }
16 | //=========================================================================================
17 | public SingleElement(ElementContent content)
18 | : base(null)
19 | {
20 | this.Content = content;
21 | this.Text = string.Empty;
22 | }
23 | //=========================================================================================
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/TextStyle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 |
4 | namespace SA.CodeView
5 | {
6 | public class TextStyle
7 | {
8 | public Color ForeColor;
9 | public readonly string Name;
10 | //=========================================================================================
11 | public TextStyle(string name, Color color, bool bold)
12 | {
13 | this.Name = name;
14 | this.ForeColor = color;
15 | }
16 | //=========================================================================================
17 | public TextStyle(string name, Color color)
18 | : this(name, color, false) { }
19 | //=========================================================================================
20 | public override string ToString()
21 | {
22 | return this.Name;
23 | }
24 | //=========================================================================================
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Parsing/SyntaxSettingsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 | using SA.CodeView.Utils;
4 |
5 | namespace Tests.Parsing
6 | {
7 | /// Тесты класса SyntaxSettings.
8 | [TestFixture]
9 | public class SyntaxSettingsTests
10 | {
11 | //=========================================================================================
12 | /// Проверяем, как извлекаются слова из переданного текста.
13 | [Test]
14 | public void GetKeywordsFromText()
15 | {
16 | string sText = " GO\tя12\r\n\tANY ";
17 | List words = new List();
18 | foreach (string sWord in TextSplitter.GetWordsFromText(sText))
19 | words.Add(sWord);
20 | Assert.That(words, Is.EquivalentTo(new string[] { "GO", "я12", "ANY" }));
21 | }
22 | //=========================================================================================
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/SmallTypes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView
4 | {
5 | //#############################################################################################
6 | enum CaretLocationType
7 | {
8 | WordStart,
9 | WordCenter,
10 | WordEnd,
11 | BetweenWords,
12 | }
13 | //#############################################################################################
14 | struct CaretLocation
15 | {
16 | public CaretLocationType Location;
17 | public int TokenIndex;
18 | //=========================================================================================
19 | public CaretLocation(int tokenIndex, CaretLocationType type)
20 | {
21 | this.TokenIndex = tokenIndex;
22 | this.Location = type;
23 | }
24 | //=========================================================================================
25 | public override string ToString()
26 | {
27 | return string.Format("{0}, {1}", this.TokenIndex, this.Location);
28 | }
29 | //=========================================================================================
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SA.CodeView/Editing/ClipboardProxyClass.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Forms;
2 |
3 | namespace SA.CodeView.Editing
4 | {
5 | public interface IClipboard
6 | {
7 | bool ContainsText();
8 | string GetText();
9 | void SetText(string text);
10 | }
11 |
12 | /// Allow access to clipboard.
13 | class ClipboardProxyClass : IClipboard
14 | {
15 | public static readonly ClipboardProxyClass Self = new ClipboardProxyClass();
16 | //=========================================================================================
17 | public bool ContainsText()
18 | {
19 | return Clipboard.ContainsText();
20 | }
21 | //=========================================================================================
22 | public string GetText()
23 | {
24 | return Clipboard.GetText();
25 | }
26 | //=========================================================================================
27 | public void SetText(string text)
28 | {
29 | Clipboard.SetText(text);
30 | }
31 | //=========================================================================================
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/WhereSuggestionBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.IntelliSense
4 | {
5 | public class WhereSuggestionBuilder : SuggestionBuilder
6 | {
7 | readonly IDbInfoProvider InfoProvider;
8 | //=========================================================================================
9 | readonly string Schema;
10 | readonly string Table;
11 | //=========================================================================================
12 | public WhereSuggestionBuilder(CodeViewer viewer, IDbInfoProvider infoProvider, string schema, string table)
13 | : base(viewer)
14 | {
15 | this.InfoProvider = infoProvider;
16 | this.Schema = schema;
17 | this.Table = table;
18 | }
19 | //=========================================================================================
20 | public override CompletionVariantList GetVariants()
21 | {
22 | CompletionVariantList items = null;
23 | var names = this.InfoProvider.GetColumnsFor(this.Schema, this.Table);
24 | items = CompletionVariantList.Combine(items, names, DataBaseLevel.Columns);
25 |
26 | return items;
27 | }
28 | //=========================================================================================
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/IntelliSense/BasicTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NUnit.Framework;
3 | using SA.CodeView;
4 | using NUnit.Framework.SyntaxHelpers;
5 | using SA.CodeView.IntelliSense;
6 | using System.Windows.Forms;
7 | using System.Drawing;
8 | using System.Collections.Generic;
9 |
10 | namespace Tests.IntelliSense
11 | {
12 | [TestFixture]
13 | public class BasicTests
14 | {
15 | //=========================================================================================
16 | /// Инициализация.
17 | [SetUp]
18 | public void Init() { }
19 | //=========================================================================================
20 | /// Линковка.
21 | [Test]
22 | public void Linking()
23 | {
24 | CodeViewer oViewer = new CodeViewer();
25 | Assert.IsNull(oViewer.CodeCompletor);
26 |
27 | oViewer.ReadOnly = false;
28 | Assert.IsNull(oViewer.CodeCompletor);
29 |
30 | TestDbInfoProvider oTestProvider = new TestDbInfoProvider();
31 | var oSuggestionBuilder = new EditQueryRegExBuilder(oViewer, oTestProvider);
32 |
33 | oViewer.UseSuggestionRules(oSuggestionBuilder);
34 |
35 | Assert.IsNotNull(oViewer.CodeCompletor);
36 | Assert.IsNotNull(oViewer.CodeCompletor.Builder);
37 | Assert.AreEqual(oSuggestionBuilder, oViewer.CodeCompletor.Builder);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/SuggestionBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 | using System.Collections.Generic;
4 | using SA.CodeView.Parsing;
5 |
6 | namespace SA.CodeView.IntelliSense
7 | {
8 | /// Supply suggestion list for typed text.
9 | public abstract class SuggestionBuilder
10 | {
11 | protected readonly CodeViewer Viewer;
12 | public ImageList Images { get; set; }
13 | //=========================================================================================
14 | public SuggestionBuilder(CodeViewer viewer)
15 | {
16 | this.Viewer = viewer;
17 | }
18 | //=========================================================================================
19 | /// Supply variants of auto completion.
20 | public abstract CompletionVariantList GetVariants();
21 | //=========================================================================================
22 | /// Is the token list contain specified token
23 | protected bool CheckTokenId(int iTokenId)
24 | {
25 | bool notCorrect = iTokenId < 0 || iTokenId >= this.Viewer.Tokens.Count;
26 |
27 | return !notCorrect;
28 | }
29 | //=========================================================================================
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SA.CodeView/Languages/NonSyntaxSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 | using SA.CodeView.Parsing;
4 | using SA.CodeView.ParsingOnElements;
5 |
6 | namespace SA.CodeView.Languages
7 | {
8 | class NonSyntaxSettings : SyntaxSettings
9 | {
10 | //=========================================================================================
11 | public NonSyntaxSettings()
12 | {
13 | this.Operators = new char[] { };
14 | }
15 | //=========================================================================================
16 | protected override Dictionary CreateTextStyles()
17 | {
18 | var styles = base.CreateTextStyles();
19 | this.AddStyle(styles, new TextStyle(S_OPERATORS, Color.Teal));
20 | return styles;
21 | }
22 | //=========================================================================================
23 | protected override List CreateElements()
24 | {
25 | return new List();
26 | }
27 | //=========================================================================================
28 | internal override ScannerSpecification CreateScannerSpecification()
29 | {
30 | var oSpec = new ScannerSpecification();
31 | oSpec.AddLiteral("any", CharType.AnyNonSpaces);
32 | oSpec.AddTokenDeclaration("all", "any{any}");
33 | return oSpec;
34 | }
35 | //=========================================================================================
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/CodeViewing/FontColorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using NUnit.Framework;
3 | using SA.CodeView;
4 | using SA.CodeView.Languages;
5 |
6 | namespace Tests.CodeViewing
7 | {
8 | [TestFixture]
9 | public class FontColorTests
10 | {
11 | const string Script = @"
12 | SET QUOTED_IDENTIFIER ON
13 | GO
14 | SET ANSI_NULLS ON
15 | GO
16 | CREATE VIEW [dbo].[view1] (id)
17 | as select 1
18 | GO";
19 | //=========================================================================================
20 | [Test]
21 | public void Getting_style_by_name()
22 | {
23 | CodeViewer oViewer = new CodeViewer();
24 | oViewer.Language = PredefinedLanguage.MsSql;
25 | oViewer.Text = Script;
26 |
27 | SyntaxSettings oSettings = oViewer.SyntaxSettings;
28 |
29 | TextStyle oStyle = oSettings.GetStyleByName(SyntaxSettings.S_KEYWORDS_1);
30 | Assert.AreEqual(oStyle.ForeColor, Color.Blue);
31 | }
32 | //=========================================================================================
33 | [Test]
34 | public void Change_font()
35 | {
36 | CodeViewer oViewer = new CodeViewer();
37 | oViewer.Language = PredefinedLanguage.MsSql;
38 | oViewer.Text = Script;
39 |
40 | Assert.AreEqual(oViewer.Font.Name, "Consolas");
41 | oViewer.Body.Font = new Font("Arial", 12);
42 | Assert.AreEqual(oViewer.Font.Name, "Arial");
43 | }
44 | //=========================================================================================
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Parsing/NonSyntaxSettingsTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using SA.CodeView.Languages;
3 | using SA.CodeView.Parsing;
4 |
5 | namespace Tests.Parsing
6 | {
7 | /// Тесты на разбор текста, для которого не определен язык
8 | [TestFixture]
9 | public class NonSyntaxSettingsTests
10 | {
11 | readonly StateParser Parser;
12 | //=========================================================================================
13 | public NonSyntaxSettingsTests()
14 | {
15 | this.Parser = new StateParser(new NonSyntaxSettings(), 4);
16 | }
17 | //=========================================================================================
18 | void ReadTokenWithStyle(string style, string text)
19 | {
20 | var oToken = this.Parser.GetNextToken();
21 | if (this.Parser.Errors.Count > 0)
22 | Assert.Fail(this.Parser.Errors[0]);
23 | Assert.That(oToken.Text, Is.EqualTo(text));
24 | Assert.AreEqual(oToken.Style.Name, style);
25 | }
26 | //=========================================================================================
27 | /// Текст должен разбиваться на токены по словам.
28 | [Test]
29 | public void Split_to_words()
30 | {
31 | this.Parser.SetSource("select 1+2\ttest()");
32 | this.ReadTokenWithStyle("Normal", "select");
33 | this.ReadTokenWithStyle("Normal", "1+2");
34 | this.ReadTokenWithStyle("Normal", "test()");
35 | }
36 | //=========================================================================================
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/Token.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.Parsing
4 | {
5 | /// Фрагмент текста, имеющий координаты в исходном тексте и обладающий собственным стилем отображения.
6 | public class Token
7 | {
8 | /// Указатель на начало подстроки в исходном тексте.
9 | public readonly TextPoint Start;
10 | /// Указатель на символ, следующий за последним.
11 | public readonly TextPoint End;
12 | /// Стиль отображения текста токена.
13 | public TextStyle Style { get; internal set; }
14 | /// Текст, составляющий токен.
15 | public readonly string Text;
16 | /// Название токена, характеризующее его тип.
17 | public readonly string TokenTypeName;
18 | //=========================================================================================
19 | public Token(string typeName, string text, TextPoint start, TextPoint end, TextStyle style)
20 | {
21 | this.TokenTypeName = typeName;
22 | this.Text = text;
23 | this.Start = start;
24 | this.End = end;
25 | this.Style = style;
26 | }
27 | //=========================================================================================
28 | public Token(string text, TextPoint start, TextPoint end, TextStyle style)
29 | : this(null, text, start, end, style)
30 | {
31 | }
32 | //=========================================================================================
33 | public override string ToString()
34 | {
35 | if (this.Style == null)
36 | return this.Text;
37 | else
38 | return string.Format("{0} - {1}", this.Style.Name, this.Text);
39 | }
40 | //=========================================================================================
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParsingOnElements (obsolete)/BoundedElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.ParsingOnElements
4 | {
5 | /// Правило, по которому токен должен иметь определенные начальные и конечные символы.
6 | class BoundedElement : BaseElement
7 | {
8 | public readonly TextStyle BoundStyle;
9 | /// Текст токена должен начинаться с этих символов.
10 | public readonly string StartSymbols;
11 | /// Текст токена должен завершаться этими символами. Если это поле пустое, то токен длится до конца строки.
12 | public readonly string EndSymbols;
13 | /// Указывает, как можно вставить в текст завершающие символы, так чтобы они не считались завершающими.
14 | public readonly string Escape;
15 | //=========================================================================================
16 | public BoundedElement(TextStyle style, string startSymbols, string endSymbols, string escape)
17 | : this(style, (TextStyle)null, startSymbols, endSymbols)
18 | {
19 | this.Escape = escape;
20 | }
21 | //=========================================================================================
22 | public BoundedElement(TextStyle style, string startSymbols, string endSymbols)
23 | : this(style, (TextStyle)null, startSymbols, endSymbols) { }
24 | //=========================================================================================
25 | public BoundedElement(TextStyle bodyStyle, TextStyle boundStyle, string startSymbols, string endSymbols)
26 | : base(bodyStyle)
27 | {
28 | this.BoundStyle = boundStyle;
29 | this.StartSymbols = startSymbols;
30 | this.EndSymbols = endSymbols;
31 | }
32 | //=========================================================================================
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SA.CodeView
2 | C# WinForms code editor with syntax highlighting
3 |
4 | SA.CodeView is light-weight viewer and editor with syntax highlighting. It can be used as single-line text field or as fully functioned editor. It was initially developed for some application but then was segregated as standalone open-source library.
5 |
6 | ## Quick Start
7 |
8 | * Download the sources and compile SA.CodeView.dll library.
9 | * Create new Windows Forms project and open Form1.cs designer view.
10 | * Toolbox panel -> right click -> Choose Items... -> Browse. CodeViewer control should appear.
11 | * Drag and drop CodeViewer into the form.
12 | * Specify Language property, compile the project.
13 |
14 | ## Features
15 | * **Line Numbers**. Just Set ShowLineNumbers = true.
16 | * **"Find Text" window**. Invoke ShowFind() method from your code.
17 |
18 | 
19 |
20 | * **Current line highlighting**. Turn on HighlightCurrentLine property.
21 |
22 | 
23 |
24 | * **Ability to change background and border for some text fragments**. Spans can be used for this purpose. The span is part of the text with specified background and border color. Add items to Spans collection to use this feature:
25 | ```csharp
26 | codeViewer.Text = "Span sample";
27 | codeViewer.Spans.Add(Brushes.LightGreen, 0, 2, 7);
28 | ```
29 |
30 | 
31 |
32 | * **Syntax highlighting**. SA.CodeView has expandable system of different languages support. It also supports predefined support of XML and different dialects of SQL. To enable syntax highlighting select on of predefined languages:
33 | ```csharp
34 | codeViewer.Language = PredefinedLanguage.MsSql;
35 | ```
36 |
37 | 
38 |
39 | or implement your own implementation.
40 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/Literal.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.Parsing
4 | {
5 | /// Определяет класс символа во входном потоке.
6 | class Literal
7 | {
8 | /// Имя литерала.
9 | public readonly string Name;
10 | /// Маска типов символа, которые будут являться данным литералом.
11 | public readonly CharType CharTypes;
12 | /// Если символ является одним из перечисленных, то это наш литерал.
13 | public readonly char[] Chars;
14 | //=========================================================================================
15 | private CharType GetCharType(char c)
16 | {
17 | if (char.IsLetter(c))
18 | return CharType.Letters;
19 | if (char.IsDigit(c))
20 | return CharType.Numbers;
21 | return CharType.Unknown;
22 | }
23 | //=========================================================================================
24 | public Literal(string name, CharType charTypes, params char[] chars)
25 | {
26 | this.Name = name;
27 | this.Chars = chars;
28 | this.CharTypes = charTypes;
29 | }
30 | //=========================================================================================
31 | public Literal(string name, params char[] chars)
32 | {
33 | this.Name = name;
34 | this.Chars = chars;
35 | }
36 | //=========================================================================================
37 | /// Является ли указанный символ нашим литералам.
38 | internal bool IsValid(char c)
39 | {
40 | if (this.CharTypes != 0)
41 | {
42 | if ((this.CharTypes & CharType.AnyNonSpaces) != 0)
43 | return !char.IsWhiteSpace(c);
44 | CharType charType = this.GetCharType(c);
45 | if ((this.CharTypes & charType) != 0)
46 | return true;
47 | }
48 | for (int i = 0; i < this.Chars.Length; i++)
49 | {
50 | if (c == this.Chars[i])
51 | return true;
52 | }
53 | return false;
54 | }
55 | //=========================================================================================
56 | public override string ToString()
57 | {
58 | return this.Name;
59 | }
60 | //=========================================================================================
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/ParserSpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.Parsing
5 | {
6 | /// Определяет конечный автомат для работы парсера.
7 | class ParserSpecification
8 | {
9 | public readonly List States;
10 | /// Стартовое состояние любого разбора.
11 | public readonly StateParserState StartState;
12 | /// Конечное состояние любого разбора.
13 | public readonly StateParserState EndState;
14 | public readonly StateParserState FailState;
15 | //=========================================================================================
16 | public ParserSpecification()
17 | {
18 | this.States = new List();
19 | this.StartState = new StateParserState("");
20 | this.EndState = new StateParserState("");
21 | this.FailState = new StateParserState("");
22 | this.States.Add(this.StartState);
23 | this.States.Add(this.EndState);
24 | this.States.Add(this.FailState);
25 |
26 | this.StartState.SetDefaultLink(this.FailState);
27 | this.FailState.SetDefaultLink(this.EndState);
28 | }
29 | //=========================================================================================
30 | /// Добавить правило разбора.
31 | internal void AddRule(string name, string definition)
32 | {
33 | var oScanner = new SA.CodeView.Parsing.RuleDefParsing.Scanner(definition, string.Empty);
34 | var oParser = new SA.CodeView.Parsing.RuleDefParsing.Parser(oScanner);
35 |
36 | int iStartStatesCount = this.States.Count;
37 |
38 | oParser.Spec = this;
39 | oParser.Parse();
40 |
41 | ///Для всех состояний, у которых не определено ни одного перехода, определяем его на EndState.
42 | for (int iState = iStartStatesCount; iState < this.States.Count; iState++)
43 | {
44 | var oState = this.States[iState];
45 | if (oState.Entries.Count == 0 && oState.ElseState == null)
46 | oState.SetDefaultLink(this.EndState);
47 | oState.ResultTokenName = name;
48 | }
49 |
50 | if (oParser.Errors.Count != 0)
51 | throw new ArgumentException(oParser.Errors[0].Msg);
52 | }
53 | //=========================================================================================
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/Visual/IntellisenseMessageFilter.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using System.Windows.Forms;
3 |
4 | namespace SA.CodeView.IntelliSense
5 | {
6 | class IntellisenseMessageFilter : IMessageFilter
7 | {
8 | #region WinAPI Constants
9 |
10 | private const int WM_MOUSEWHEEL = 0x020A;
11 |
12 | private const int WM_LBUTTONDOWN = 0x0201;
13 |
14 | #endregion
15 | //============================================================================================
16 | /// Хранит объект формы
17 | private readonly IntellisenseForm IntelForm;
18 | //============================================================================================
19 | public IntellisenseMessageFilter(IntellisenseForm form)
20 | {
21 | this.IntelForm = form;
22 | }
23 | //============================================================================================
24 | /// Интерфейсный метод обработки сообщений
25 | public bool PreFilterMessage(ref Message m)
26 | {
27 | if (m.Msg == WM_LBUTTONDOWN)
28 | {
29 | return ProcessLButtonDown(m);
30 | }
31 |
32 | if (m.Msg == WM_MOUSEWHEEL)
33 | {
34 | return ProcessMouseWheel(m);
35 | }
36 |
37 | return false;
38 | }
39 | //============================================================================================
40 | /// Обрабатывает сообщения вращения колесика мышки
41 | private bool ProcessMouseWheel(Message m)
42 | {
43 | int wheelDelta = WinAPI.GetWheelDelta_WParam(m.WParam);
44 |
45 | Point point = WinAPI.GetPointFromLParam(m.LParam);
46 |
47 | this.IntelForm.listItems.ScrollListView(wheelDelta);
48 |
49 | return true;
50 | }
51 | //============================================================================================
52 | /// Обрабатывает нажатия левой кнопки мыши
53 | private bool ProcessLButtonDown(Message m)
54 | {
55 | Point point = WinAPI.GetPointFromLParam(m.LParam);
56 |
57 | bool isIntelFormHandle = m.HWnd != this.IntelForm.Handle;
58 | bool isIntelListViewHandle = m.HWnd != this.IntelForm.listItems.Handle;
59 |
60 | if (isIntelFormHandle && isIntelListViewHandle)
61 | this.IntelForm.HideList();
62 |
63 | return false;
64 | }
65 | //============================================================================================
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/CodeViewing/RendererTests.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using Moq;
3 | using NUnit.Framework;
4 | using SA.CodeView;
5 |
6 | namespace Tests.CodeViewing
7 | {
8 | [TestFixture]
9 | public class RendererTests
10 | {
11 | CodeViewer Viewer;
12 | Graphics MyGraphics;
13 | //=========================================================================================
14 | public RendererTests()
15 | {
16 | this.Viewer = new CodeViewer();
17 | this.Viewer.Language = PredefinedLanguage.MsSql;
18 | this.Viewer.Size = new Size(400, 400);
19 |
20 | Bitmap oBitmap = new Bitmap(1, 1);
21 | this.MyGraphics = Graphics.FromImage(oBitmap);
22 | }
23 | //=========================================================================================
24 | [Test]
25 | public void Draw_token_with_selection_in_the_middle()
26 | {
27 | ///Arrange
28 | this.Viewer.Text = "select";
29 | this.Viewer.Caret.MoveToPos(0, 2, true);
30 | this.Viewer.Caret.MoveToPos(0, 5, false);
31 | var oRenderer = new Mock(this.Viewer);
32 |
33 | ///Act
34 | oRenderer.Object.DrawLinesWithSelection(new Point(), this.MyGraphics);
35 |
36 | ///Assert
37 | oRenderer.Verify(x => x.DrawText(
38 | this.MyGraphics,
39 | "lec",
40 | 2,
41 | It.IsAny(),
42 | It.IsAny()));
43 |
44 | oRenderer.Verify(x => x.DrawText(
45 | this.MyGraphics,
46 | "se",
47 | 0,
48 | It.IsAny(),
49 | It.IsAny()));
50 |
51 | oRenderer.Verify(x => x.DrawText(
52 | this.MyGraphics,
53 | "t",
54 | 5,
55 | It.IsAny(),
56 | It.IsAny()));
57 | }
58 | //=========================================================================================
59 | [Test]
60 | public void Draw_token_when_selected_caret_return_and_start_of_line()
61 | {
62 | ///Arrange
63 | this.Viewer.Text = "ab\r\ncde";
64 | this.Viewer.Caret.MoveToPos(0, 2, true);
65 | this.Viewer.Caret.MoveDocEnd(false);
66 |
67 | var oRenderer = new Mock(this.Viewer);
68 |
69 | ///Act
70 | oRenderer.Object.DrawLinesWithSelection(new Point(), this.MyGraphics);
71 |
72 | ///Assert
73 | //Check that 'cde' text was rendered at 0 position
74 | oRenderer.Verify(x => x.DrawText(
75 | this.MyGraphics,
76 | "cde",
77 | 0,
78 | It.IsAny(),
79 | It.IsAny()));
80 |
81 | //There were 2 invocations of drawing
82 | oRenderer.Verify(x => x.DrawText(
83 | this.MyGraphics,
84 | It.IsAny(),
85 | It.IsAny(),
86 | It.IsAny(),
87 | It.IsAny()), Times.Exactly(2));
88 | }
89 | //=========================================================================================
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/StateParserState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.Parsing
5 | {
6 | internal class StateParserState
7 | {
8 | public readonly string Name;
9 | internal Dictionary Entries;
10 | internal StateParserState ElseState;
11 | internal string ResultTokenName;
12 | internal string StyleName;
13 | string _ExpectationString;
14 | //=========================================================================================
15 | public StateParserState(string name)
16 | {
17 | this.Entries = new Dictionary();
18 | this.Name = name;
19 | }
20 | //=========================================================================================
21 | public StateParserState GetNextState(Token token)
22 | {
23 | foreach (var oEntry in this.Entries)
24 | {
25 | if (string.Compare(oEntry.Key, token.TokenTypeName, true) == 0)
26 | return oEntry.Value;
27 | }
28 | return this.ElseState;
29 | }
30 | //=========================================================================================
31 | internal void AddLink(string tokenType, StateParserState state)
32 | {
33 | this.Entries.Add(tokenType, state);
34 | }
35 | //=========================================================================================
36 | /// Переход по умолчанию, который выполняется, если не срабатывают условия других переходов.
37 | internal void SetDefaultLink(StateParserState state)
38 | {
39 | this.ElseState = state;
40 | }
41 | //=========================================================================================
42 | public override string ToString()
43 | {
44 | return this.Name;
45 | }
46 | //=========================================================================================
47 | /// Получить текстовое описание ожидаемых литералов.
48 | internal string GetExpectationToString()
49 | {
50 | if (_ExpectationString == null)
51 | {
52 | System.Text.StringBuilder sb = new System.Text.StringBuilder("Expected ");
53 | if (this.Entries.Count == 0)
54 | {
55 | if (this.ElseState != null)
56 | sb.AppendFormat("'{0}'", this.ElseState.Name);
57 | else
58 | throw new NullReferenceException("Links for " + this.Name);
59 | }
60 | bool bFirst = true;
61 | foreach (var oKey in this.Entries.Keys)
62 | {
63 | if (bFirst)
64 | bFirst = false;
65 | else
66 | sb.Append(" or ");
67 | sb.AppendFormat("'{0}'", oKey);
68 | }
69 | this._ExpectationString = sb.ToString();
70 | }
71 | return this._ExpectationString;
72 | }
73 | //=========================================================================================
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Parsing/StateParserTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using SA.CodeView.Parsing;
3 |
4 | namespace Tests.Parsing
5 | {
6 | [TestFixture]
7 | public class StateParserTests
8 | {
9 | //=========================================================================================
10 | void ReadAndAssertToken(StateParser parser, string tokenType, string text)
11 | {
12 | var oToken = parser.GetNextToken();
13 | Assert.That(parser.Errors, Has.Count);
14 | Assert.That(oToken.Text, Is.EqualTo(text));
15 | Assert.That(oToken.TokenTypeName, Is.EqualTo(tokenType));
16 | }
17 | //=========================================================================================
18 | void ReadTokenWithStyle(StateParser parser, string style, string text)
19 | {
20 | var oToken = parser.GetNextToken();
21 | Assert.That(parser.Errors, Has.Count);
22 | Assert.That(oToken.Text, Is.EqualTo(text));
23 | Assert.AreEqual(oToken.Style.Name, style);
24 |
25 | //Assert.That(oToken.TokenTypeName, Is.EqualTo(tokenType));
26 | }
27 | //=========================================================================================
28 | /// Читаем последовательность токенов, описывающих присваивание переменной числу.
29 | [Test]
30 | public void VariablesAssignment()
31 | {
32 | ScannerSpecification oSpec = new ScannerSpecification();
33 | oSpec.AddLiteral("l", CharType.Letters, '_');
34 | oSpec.AddLiteral("d", CharType.Numbers);
35 | oSpec.AddLiteral("x", '=', ';');
36 |
37 | oSpec.AddTokenDeclaration("id", "l{l|d}");
38 | oSpec.AddTokenDeclaration("number", "d{d}");
39 | oSpec.AddTokenDeclaration("sep", "x");
40 |
41 | StateParser oStateParser = new StateParser(new StateScanner(oSpec, 4));
42 | oStateParser.Spec.AddRule("Tag", "id sep number sep");
43 |
44 | {
45 | oStateParser.SetSource("sText=10;");
46 | this.ReadAndAssertToken(oStateParser, "id", "sText");
47 | this.ReadAndAssertToken(oStateParser, "sep", "=");
48 | this.ReadAndAssertToken(oStateParser, "number", "10");
49 | this.ReadAndAssertToken(oStateParser, "sep", ";");
50 | var oToken = oStateParser.GetNextToken();
51 | Assert.IsNull(oToken);
52 | }
53 | }
54 | //=========================================================================================
55 | /// Многострочные токены должны разбиваться по числу строк.
56 | [Test]
57 | public void MultiLineTokens()
58 | {
59 | ScannerSpecification oSpec = new ScannerSpecification();
60 | oSpec.AddLiteral("l", CharType.Letters, '_');
61 | oSpec.AddLiteral("d", CharType.Numbers);
62 | oSpec.AddLiteral("br1", '[');
63 | oSpec.AddLiteral("br2", ']');
64 |
65 | oSpec.AddTokenDeclaration("id", "l{l|d}");
66 | oSpec.AddBoundedToken("id2", "br1", "br2", null);
67 |
68 |
69 | StateParser oStateParser = new StateParser(new StateScanner(oSpec, 4));
70 | oStateParser.Spec.AddRule("id", "id|id2");
71 |
72 | {
73 | oStateParser.SetSource(
74 | @"select [
75 | x int] from x
76 | ");
77 | this.ReadAndAssertToken(oStateParser, "id", "select");
78 | this.ReadAndAssertToken(oStateParser, "id2", "[");
79 | this.ReadAndAssertToken(oStateParser, "id2", " x int]");
80 | }
81 | }
82 | //=========================================================================================
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/IntelliSense/CodeViewerTokenIndexTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using SA.CodeView;
3 | using SA.CodeView.IntelliSense;
4 | using Tests.IntelliSense.BLL;
5 |
6 | namespace Tests.IntelliSense
7 | {
8 | /// Current token detection.
9 | [TestFixture]
10 | public class CodeViewerTokenIndexTests
11 | {
12 | private readonly CodeViewer Viewer;
13 | //=========================================================================================
14 | public CodeViewerTokenIndexTests()
15 | {
16 | this.Viewer = new CodeViewer();
17 | this.Viewer.Language = PredefinedLanguage.MsSql;
18 | var oTestProvider = new TestDbInfoProvider();
19 | var oSuggestionBuilder = new EditQueryRegExBuilder(this.Viewer, oTestProvider);
20 | this.Viewer.UseSuggestionRules(oSuggestionBuilder);
21 | }
22 | //=========================================================================================
23 | [Test]
24 | public void Detect_caret_location_when_doc_is_empty()
25 | {
26 | this.Viewer.Text = "";
27 | Assert.AreEqual(-1, Viewer.Caret.TokenIndex);
28 | }
29 | //=========================================================================================
30 | [Test]
31 | public void Detect_caret_location_at_the_end_of_document_after_several_whitespaces()
32 | {
33 | this.Viewer.Text = "select * from \t ";
34 |
35 | this.Viewer.Caret.MoveDocEnd(true);
36 | Assert.AreEqual(2, Viewer.Caret.TokenIndex);
37 | Assert.AreEqual(CaretLocationType.BetweenWords, Viewer.Caret.RegardingToken);
38 | }
39 | //=========================================================================================
40 | [Test]
41 | public void Detect_caret_location_between_2_words()
42 | {
43 | this.Viewer.Text = "select from";
44 | this.Viewer.Caret.MoveToPos(0, "select ".Length, true);
45 |
46 | Assert.AreEqual(0, this.Viewer.Caret.TokenIndex);
47 | Assert.AreEqual(CaretLocationType.BetweenWords, this.Viewer.Caret.RegardingToken);
48 | }
49 | //=========================================================================================
50 | [Test]
51 | public void Detect_caret_location_at_the_beginning_of_the_token()
52 | {
53 | this.Viewer.Text = "select user_name from \t ";
54 |
55 | this.Viewer.Caret.MoveToPos(0, "select ".Length, true);
56 | Assert.AreEqual(1, this.Viewer.Caret.TokenIndex);
57 | Assert.AreEqual(CaretLocationType.WordStart, this.Viewer.Caret.RegardingToken);
58 | }
59 | //=========================================================================================
60 | [Test]
61 | public void Detect_caret_location_at_the_end_of_the_token()
62 | {
63 | this.Viewer.Text = "select user_name from \t ";
64 |
65 | this.Viewer.Caret.MoveToPos(0, "select user_name".Length, true);
66 | Assert.AreEqual(1, this.Viewer.Caret.TokenIndex);
67 | Assert.AreEqual(CaretLocationType.WordEnd, this.Viewer.Caret.RegardingToken);
68 | }
69 | //=========================================================================================
70 | [Test]
71 | public void Detect_caret_location_in_the_middle_of_the_token()
72 | {
73 | this.Viewer.Text = "select user_name from \t ";
74 |
75 | this.Viewer.Caret.MoveToPos(0, "select user_name fr".Length, true);
76 | Assert.AreEqual(2, this.Viewer.Caret.TokenIndex);
77 | Assert.AreEqual(CaretLocationType.WordCenter, this.Viewer.Caret.RegardingToken);
78 | }
79 | //=========================================================================================
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/StateScannerState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.Parsing
5 | {
6 | class StateScannerState
7 | {
8 | public readonly string Name;
9 | internal Dictionary Entries;
10 | internal StateScannerState ElseState;
11 | internal string ResultTokenName;
12 | /// Длина начального ограничителя.
13 | internal int StartLimiterLength;
14 | /// Длина конечного ограничителя.
15 | internal int EndLimiterLength;
16 | //=========================================================================================
17 | public StateScannerState(string name)
18 | {
19 | this.Entries = new Dictionary();
20 | this.Name = name;
21 | }
22 | //=========================================================================================
23 | public StateScannerState GetNextState(char nextChar)
24 | {
25 | ///Сначала проверяем те переходы, для которых указаны конкретные символы
26 | int iCount = 0;
27 | foreach (var oEntry in this.Entries)
28 | if (oEntry.Key.CharTypes == 0)
29 | {
30 | if (oEntry.Key.IsValid(nextChar))
31 | return oEntry.Value;
32 | iCount++;
33 | }
34 |
35 | ///Если еще остались переходы, то проверяем оставшиеся переходы - для которых указаны типы символов
36 | if (iCount < this.Entries.Count)
37 | {
38 | foreach (var oEntry in this.Entries)
39 | if (oEntry.Key.CharTypes != 0)
40 | {
41 | if (oEntry.Key.IsValid(nextChar))
42 | return oEntry.Value;
43 | }
44 | }
45 |
46 | return this.ElseState;
47 | }
48 | //=========================================================================================
49 | public StateScannerState GetNextState(Literal literal)
50 | {
51 | foreach (var oEntry in this.Entries)
52 | {
53 | if (string.Compare(oEntry.Key.Name, literal.Name, true) == 0)
54 | return oEntry.Value;
55 | }
56 | return this.ElseState;
57 | }
58 | //=========================================================================================
59 | internal void AddLink(Literal literal, StateScannerState state)
60 | {
61 | this.Entries.Add(literal, state);
62 | }
63 | //=========================================================================================
64 | /// Переход по умолчанию, который выполняется, если не срабатывают условия других переходов.
65 | internal void SetDefaultLink(StateScannerState state)
66 | {
67 | this.ElseState = state;
68 | }
69 | //=========================================================================================
70 | public override string ToString()
71 | {
72 | return this.Name;
73 | }
74 | //=========================================================================================
75 | /// Получить текстовое описание ожидаемых литералов.
76 | internal string GetExpectationToString()
77 | {
78 | System.Text.StringBuilder sb = new System.Text.StringBuilder("Expected ");
79 | if (this.Entries.Count == 0)
80 | {
81 | if (this.ElseState != null)
82 | sb.Append(this.ElseState.Name);
83 | else
84 | throw new NullReferenceException("Links for " + this.Name);
85 | }
86 | bool bFirst = true;
87 | foreach (var oKey in this.Entries.Keys)
88 | {
89 | if (bFirst)
90 | bFirst = false;
91 | else
92 | sb.Append(" or ");
93 | sb.Append(oKey.Name);
94 | }
95 | return sb.ToString();
96 | }
97 | //=========================================================================================
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/TextFinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView
4 | {
5 | /// Find and selected specified text part in the document
6 | public class TextFinder
7 | {
8 | /// Assosiated text viewer
9 | private readonly CodeViewer Viewer;
10 | /// What should be found
11 | private string FindText;
12 | private bool MatchCase;
13 | private bool MatchWord;
14 | private StringComparison comparisionMode;
15 | //=========================================================================================
16 | public TextFinder(CodeViewer viewer)
17 | {
18 | this.Viewer = viewer;
19 | }
20 | //=========================================================================================
21 | /// Find and select next fragment
22 | public void FindNext(string text, bool matchCase, bool matchWord)
23 | {
24 | this.FindText = text;
25 | this.MatchCase = matchCase;
26 | this.MatchWord = matchWord;
27 | this.comparisionMode = this.MatchCase ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase;
28 |
29 | //Start search from caret position
30 | int iStartLine = this.Viewer.Caret.Line;
31 | int iStartCol = this.Viewer.Caret.Col;
32 |
33 | if (this.FindInLine(iStartLine, iStartCol))
34 | return;
35 |
36 | for (int index = iStartLine + 1; index < this.Viewer.Document.Count; index++)
37 | if (this.FindInLine(index, 0))
38 | return;
39 | }
40 | //=========================================================================================
41 | private bool FindInLine(int line, int col)
42 | {
43 | int iStartCol = col;
44 | while (iStartCol + this.FindText.Length < this.Viewer.Document[line].Text.Length)
45 | {
46 | int iCharPos = this.Viewer.Document[line].Text.IndexOf(this.FindText, iStartCol, this.comparisionMode);
47 |
48 | if (iCharPos < 0)
49 | return false;
50 |
51 | if (!this.MatchWord)
52 | {
53 | SelectFindText(line, iCharPos);
54 | return true;
55 | }
56 |
57 | //if MatchWord option is enabled then check the fragment bounds
58 | if (iCharPos > 0)
59 | {
60 | //check left bound
61 | char leftChar = this.Viewer.Document[line].Text[iCharPos - 1];
62 | if (Char.IsLetterOrDigit(leftChar))
63 | {
64 | iStartCol = iCharPos + this.FindText.Length;
65 | continue;
66 | }
67 | }
68 |
69 | //check right bound
70 | if (iCharPos + this.FindText.Length < this.Viewer.Document[line].Text.Length - 1)
71 | {
72 | char rightChar = this.Viewer.Document[line].Text[iCharPos + this.FindText.Length];
73 | if (Char.IsLetterOrDigit(rightChar))
74 | {
75 | iStartCol = iCharPos + this.FindText.Length;
76 | continue;
77 | }
78 | }
79 |
80 | //select fragment
81 | SelectFindText(line, iCharPos);
82 | return true;
83 | }
84 |
85 | //fragment was not found
86 | return false;
87 | }
88 | //=========================================================================================
89 | /// Make specified text fragment selected
90 | /// Number of line with the text
91 | /// start position of the text
92 | private void SelectFindText(int line, int startCharPos)
93 | {
94 | int iColPos = this.Viewer.Caret.GetColumn(this.Viewer.Document[line].Text, startCharPos);
95 | this.Viewer.Caret.MoveToPos(line, iColPos, true);
96 | this.Viewer.Caret.MoveToPos(line, iColPos + this.FindText.Length, false);
97 | this.Viewer.ScrollIntoView();
98 | this.Viewer.Focus();
99 | }
100 | //=========================================================================================
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # SuperCharger files
5 | *.csdat
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.sln.docstates
11 | *.pubxml.user
12 |
13 | # Build results
14 |
15 | [Dd]ebug/
16 | [Rr]elease/
17 | x64/
18 | build/
19 | [Bb]in/
20 | [Oo]bj/
21 |
22 | # Visual Studio 2015 cache/options directory
23 | .vs/
24 | node_modules/
25 |
26 | Resharper DotSettings
27 | *.DotSettings
28 |
29 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
30 | !packages/*/build/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | *_i.c
37 | *_p.c
38 | *.ilk
39 | *.meta
40 | *.obj
41 | *.pch
42 | *.pdb
43 | *.pgc
44 | *.pgd
45 | *.rsp
46 | *.sbr
47 | *.tlb
48 | *.tli
49 | *.tlh
50 | *.tmp
51 | *.tmp_proj
52 | *.log
53 | *.vspscc
54 | *.vssscc
55 | .builds
56 | *.pidb
57 | *.log
58 | *.scc
59 |
60 | # Visual C++ cache files
61 | ipch/
62 | *.aps
63 | *.ncb
64 | *.opensdf
65 | *.sdf
66 | *.cachefile
67 |
68 | # Visual Studio profiler
69 | *.psess
70 | *.vsp
71 | *.vspx
72 |
73 | # Guidance Automation Toolkit
74 | *.gpState
75 |
76 | # ReSharper is a .NET coding add-in
77 | _ReSharper*/
78 | *.[Rr]e[Ss]harper
79 |
80 | # TeamCity is a build add-in
81 | _TeamCity*
82 |
83 | # DotCover is a Code Coverage Tool
84 | *.dotCover
85 |
86 | # NCrunch
87 | *.ncrunch*
88 | .*crunch*.local.xml
89 |
90 | # Installshield output folder
91 | [Ee]xpress/
92 |
93 | # DocProject is a documentation generator add-in
94 | DocProject/buildhelp/
95 | DocProject/Help/*.HxT
96 | DocProject/Help/*.HxC
97 | DocProject/Help/*.hhc
98 | DocProject/Help/*.hhk
99 | DocProject/Help/*.hhp
100 | DocProject/Help/Html2
101 | DocProject/Help/html
102 |
103 | # Click-Once directory
104 | publish/
105 |
106 | # Publish Web Output
107 | *.Publish.xml
108 |
109 | # NuGet Packages Directory
110 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
111 | packages/
112 |
113 | .nuget
114 |
115 | # Windows Azure Build Output
116 | csx
117 | *.build.csdef
118 |
119 | # Windows Store app package directory
120 | AppPackages/
121 |
122 | # Others
123 | sql/
124 | *.Cache
125 | ClientBin/
126 | [Ss]tyle[Cc]op.*
127 | ~$*
128 | *~
129 | *.dbmdl
130 | *.[Pp]ublish.xml
131 | *.pfx
132 | *.publishsettings
133 |
134 | # RIA/Silverlight projects
135 | Generated_Code/
136 |
137 | # Backup & report files from converting an old project file to a newer
138 | # Visual Studio version. Backup files are not needed, because we have git ;-)
139 | _UpgradeReport_Files/
140 | Backup*/
141 | UpgradeLog*.XML
142 | UpgradeLog*.htm
143 |
144 | *.bak
145 |
146 | # SQL Server files
147 | App_Data/*.mdf
148 | App_Data/*.ldf
149 |
150 |
151 | #LightSwitch generated files
152 | GeneratedArtifacts/
153 | _Pvt_Extensions/
154 | ModelManifest.xml
155 |
156 | # =========================
157 | # Windows detritus
158 | # =========================
159 |
160 | # Windows image file caches
161 | Thumbs.db
162 | ehthumbs.db
163 |
164 | # Folder config file
165 | Desktop.ini
166 |
167 | # Recycle Bin used on file shares
168 | $RECYCLE.BIN/
169 |
170 | # Mac desktop service store files
171 | .DS_Store
172 | Administration/Properties/PublishProfiles/15sof-admin-test01 - FTP.pubxml
173 | Administration/Properties/PublishProfiles/15sof-admin-test01 - Web Deploy.pubxml
174 | MobileServiceWebApp/Properties/PublishProfiles/test01api15sof - FTP.pubxml
175 | MobileServiceWebApp/Properties/PublishProfiles/test01api15sof - Web Deploy.pubxml
176 |
177 |
178 | WebFrontendMvc/assets/ts/**/*.js
179 | WebFrontendMvc/assets/ts/**/*.js.map
180 | 15SOF.DbSchema/15SOF.DbSchema.jfm
181 | /Database/15SOF.FaceMatcherDb/*.jfm
182 | /Database/15SOF.MainDb/*.jfm
183 | /15SOF.Scalable.FaceMatcherApp/PublishProfiles/Prod.xml
184 | /15SOF.Scalable.FaceMatcherApp/ApplicationParameters/Prod.xml
185 | /15SOF.FaceMatcherReceiver/PublishProfiles/Prod.xml
186 | /15SOF.FaceMatcherReceiver/ApplicationParameters/Prod.xml
187 | *.scmp
188 | /SelfieValidatorApp/PublishProfiles/Prod.xml
189 | /SelfieValidatorApp/ApplicationParameters/Prod.xml
190 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/TextPoint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView
5 | {
6 | /// Position in a document
7 | public struct TextPoint : IComparable
8 | {
9 | public int Line;
10 | /// Position in line.
11 | public int Col;
12 | /// Char number in line (may be differ from Col when there are tabs).
13 | public int Char;
14 | //=========================================================================================
15 | public TextPoint(int line, int col, int chr)
16 | {
17 | this.Line = line;
18 | this.Col = col;
19 | this.Char = chr;
20 | }
21 | //=========================================================================================
22 | public void SetPos(int line, int col, int chr)
23 | {
24 | this.Line = line;
25 | this.Col = col;
26 | this.Char = chr;
27 | }
28 | //=========================================================================================
29 | public override string ToString()
30 | {
31 | return string.Format("Ln:{0}, col:{1}, ch:{2}", this.Line, this.Col, this.Char);
32 | }
33 | //=========================================================================================
34 | #region Comparison operators
35 | //=========================================================================================
36 | public int CompareTo(object obj)
37 | {
38 | TextPoint oObj = (TextPoint)obj;
39 | int iRes = this.Line.CompareTo(oObj.Line);
40 | if (iRes != 0)
41 | return iRes;
42 | return this.Col.CompareTo(oObj.Col);
43 | }
44 | //=========================================================================================
45 | public static bool operator >(TextPoint first, TextPoint second)
46 | {
47 | return first.CompareTo(second) > 0;
48 | }
49 | //=========================================================================================
50 | public static bool operator <(TextPoint first, TextPoint second)
51 | {
52 | return first.CompareTo(second) < 0;
53 | }
54 | //=========================================================================================
55 | public static bool operator >=(TextPoint first, TextPoint second)
56 | {
57 | return first.CompareTo(second) >= 0;
58 | }
59 | //=========================================================================================
60 | public static bool operator <=(TextPoint first, TextPoint second)
61 | {
62 | return first.CompareTo(second) <= 0;
63 | }
64 | //=========================================================================================
65 | public static bool operator ==(TextPoint first, TextPoint second)
66 | {
67 | return first.CompareTo(second) == 0;
68 | }
69 | //=========================================================================================
70 | public static bool operator !=(TextPoint first, TextPoint second)
71 | {
72 | return first.CompareTo(second) != 0;
73 | }
74 | //=========================================================================================
75 | public static TextPoint Min(TextPoint first, TextPoint second)
76 | {
77 | return first.CompareTo(second) <= 0 ? first : second;
78 | }
79 | //=========================================================================================
80 | public static TextPoint Max(TextPoint first, TextPoint second)
81 | {
82 | return first.CompareTo(second) >= 0 ? first : second;
83 | }
84 | //=========================================================================================
85 | #endregion
86 | //=========================================================================================
87 | public override int GetHashCode()
88 | {
89 | return base.GetHashCode();
90 | }
91 | //=========================================================================================
92 | public override bool Equals(object obj)
93 | {
94 | TextPoint second = (TextPoint)obj;
95 | return
96 | this.Line == second.Line &&
97 | this.Char == second.Char;
98 | }
99 | //=========================================================================================
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/BufferReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.Parsing
4 | {
5 | interface IBufferReader
6 | {
7 | /// Прочитать очередной символ из потока.
8 | char ReadChar();
9 | /// Вернуться назад на один символ.
10 | void BackToChar();
11 | /// Получить подстроку в указанных границах.
12 | string GetSubstring(int start, int length);
13 | /// Текущее смещение от начала потока.
14 | int Position { get; }
15 | /// Номер текущего символа в текущей строке.
16 | int CharInLine { get; }
17 | /// Текущая колонка в текущей строке.
18 | int Column { get; }
19 | /// Номер текущей строки.
20 | int Line { get; }
21 | TextPoint Point { get; }
22 | TextPoint PreviousPoint { get; }
23 | void SetSource(string text);
24 | }
25 | //#############################################################################################
26 | /// Поставляет символы на вход сканера.
27 | class BufferReader : IBufferReader
28 | {
29 | string Text;
30 | /// Размер табуляции в символах.
31 | readonly int TabSize;
32 | /// Описывает текущие координаты в многострочном тексте.
33 | TextPoint _CurPoint;
34 | /// Описывает координаты в многострочном тексте предыдущего символа.
35 | TextPoint _PrevPoint;
36 | /// Текущее смещение от начала текста.
37 | int _Position;
38 | //=========================================================================================
39 | /// Текущая позиция во входном потоке.
40 | public int Position { get { return _Position; } }
41 | public int CharInLine { get { return this._CurPoint.Char; } }
42 | public int Column { get { return this._CurPoint.Col; } }
43 | public int Line { get { return this._CurPoint.Line; } }
44 | public TextPoint Point { get { return this._CurPoint; } }
45 | public TextPoint PreviousPoint { get { return this._PrevPoint; } }
46 | //=========================================================================================
47 | public BufferReader(int tabsize)
48 | {
49 | this.TabSize = tabsize;
50 | }
51 | //=========================================================================================
52 | public char ReadChar()
53 | {
54 | if (this.Position >= this.Text.Length)
55 | return '\0';
56 |
57 | this._PrevPoint = this._CurPoint;
58 |
59 | char cChar;
60 | do
61 | {
62 | if (this.Position >= this.Text.Length)
63 | return '\0';
64 | cChar = this.Text[this._Position];
65 | this._Position++;
66 |
67 | if (cChar == '\n')
68 | {
69 | this._CurPoint.Char = 0;
70 | this._CurPoint.Col = 0;
71 | this._CurPoint.Line++;
72 | }
73 | else
74 | {
75 | this._CurPoint.Char++;
76 | if (cChar == '\t')
77 | {
78 | do
79 | this._CurPoint.Col++;
80 | while (this._CurPoint.Col % this.TabSize != 0);
81 | }
82 | else
83 | this._CurPoint.Col++;
84 | }
85 | }
86 | while (cChar == '\r');
87 |
88 | return cChar;
89 | }
90 | //=========================================================================================
91 | public string GetSubstring(int start, int length)
92 | {
93 | for (int i = start + length - 1; i >= start; i--)
94 | {
95 | if (this.Text[i] == '\r')
96 | length--;
97 | else
98 | break;
99 | }
100 | return this.Text.Substring(start, length);
101 | }
102 | //=========================================================================================
103 | public void BackToChar()
104 | {
105 | if (this._Position <= 0)
106 | return;
107 | this._Position--;
108 | _CurPoint = _PrevPoint;
109 | }
110 | //=========================================================================================
111 | public void SetSource(string text)
112 | {
113 | this.Text = text;
114 | this._Position = 0;
115 | this._CurPoint = new TextPoint(0, 0, 0);
116 | this._PrevPoint = new TextPoint(0, 0, 0);
117 | }
118 | //=========================================================================================
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/IntelliSense/BLL/TestDbInfoProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using SA.CodeView.IntelliSense;
3 |
4 | namespace Tests.IntelliSense.BLL
5 | {
6 | /// Базовый класс варианта выпадающего списка
7 | abstract class BaseVariant
8 | {
9 | public string Name;
10 | }
11 | /// Класс варианта выпадающего списка со списком схем
12 | class TopLevelVariant : BaseVariant
13 | {
14 | public List Schemas;
15 | }
16 | /// Класс варианта выпадающего списка со списком таблиц
17 | class SchemaVariant : BaseVariant
18 | {
19 | public List Tables;
20 | }
21 | /// Класс варианта выпадающего списка со списком колонок
22 | class TableVariant : BaseVariant
23 | {
24 | public string[] Columns;
25 | }
26 | /// Тестовый провайдер данных БД
27 | public class TestDbInfoProvider : IDbInfoProvider
28 | {
29 | /// Тестовые данные псевдо-БД
30 | TopLevelVariant Variants;
31 | //=========================================================================================
32 | public TestDbInfoProvider()
33 | {
34 | CreateTestData();
35 | }
36 | //=========================================================================================
37 | /// Создает данные о псевдо-БД.
38 | private void CreateTestData()
39 | {
40 | TableVariant oTableUser = new TableVariant() { Name = "User", Columns = new string[] { "First Name", "Last Name" } };
41 | TableVariant oTableOrg = new TableVariant() { Name = "Org", Columns = new string[] { "Name", "Address" } };
42 |
43 | SchemaVariant oSchemaFirst = new SchemaVariant() { Name = "Schema_First", Tables = new List() { oTableUser, oTableOrg } };
44 |
45 | TableVariant oTableFruits = new TableVariant() { Name = "Fruits", Columns = new string[] { "Apple", "Lemon" } };
46 | TableVariant oTableVitamins = new TableVariant() { Name = "Vitamins", Columns = new string[] { "A", "B" } };
47 |
48 | SchemaVariant oSchemaSecond = new SchemaVariant() { Name = "Schema_Second", Tables = new List() { oTableFruits, oTableVitamins } };
49 | SchemaVariant oSchemaThird = new SchemaVariant() { Name = "Schema Third", Tables = new List() { oTableFruits, oTableVitamins } };
50 | //SchemaVariant oSchemaTest = new SchemaVariant() { Name = "Test" };
51 |
52 | this.Variants = new TopLevelVariant() { Schemas = new List() { oSchemaFirst, oSchemaSecond, oSchemaThird } };
53 | }
54 | //=========================================================================================
55 | /// Возвращает список схем.
56 | public List GetSchemas()
57 | {
58 | List items = new List();
59 |
60 | foreach (SchemaVariant var in Variants.Schemas)
61 | {
62 | items.Add(var.Name);
63 | }
64 |
65 | return items;
66 | }
67 | //=========================================================================================
68 | /// Возвращает список таблиц.
69 | public List GetObjectsInSchema(string schema)
70 | {
71 | //TODO: возвращать null, если пусто
72 | //schema = schema.Trim(new char[] { '[', ']', '~', '\'' });
73 |
74 | List items = new List();
75 |
76 | foreach (SchemaVariant var in Variants.Schemas)
77 | {
78 | bool bIsEqualSchemas = string.Compare(var.Name, schema, true) == 0;
79 | if (bIsEqualSchemas)
80 | foreach (TableVariant tableVar in var.Tables)
81 | items.Add(tableVar.Name);
82 | }
83 |
84 | return items;
85 | }
86 | //=========================================================================================
87 | /// Возвращает список колонок.
88 | public List GetColumnsFor(string schema, string table)
89 | {
90 | //schema = schema.Trim(new char[] { '[', ']', '~', '\'' });
91 | //table = table.Trim(new char[] { '[', ']', '~', '\'' });
92 |
93 | List items = new List();
94 |
95 | foreach (SchemaVariant var in Variants.Schemas)
96 | {
97 | bool isEqualSchemas = string.Compare(var.Name, schema, true) == 0;
98 | if (isEqualSchemas)
99 | {
100 | foreach (TableVariant tableVar in var.Tables)
101 | {
102 | bool isEqualTables = string.Compare(tableVar.Name, table, true) == 0;
103 | if (isEqualTables)
104 | {
105 | return new List(tableVar.Columns);
106 | }
107 | }
108 | }
109 | }
110 |
111 | return items;
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/SA.CodeView/Utils/TextSplitter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.Utils
5 | {
6 | /// Разбивает текст на нужные фрагменты.
7 | static class TextSplitter
8 | {
9 | //=========================================================================================
10 | /// Разбиваем переданный текст на слова, разделенные пробелами, табами и переводами строк.
11 | internal static IEnumerable GetWordsFromText(string text)
12 | {
13 | if (string.IsNullOrEmpty(text))
14 | yield break;
15 | int iPos = 0, iStart = char.IsWhiteSpace(text, 0) ? -1 : 0;
16 | while (iPos < text.Length)
17 | {
18 | if (iStart < 0)
19 | {
20 | if (!char.IsWhiteSpace(text, iPos))
21 | {
22 | iStart = iPos;
23 | continue;
24 | }
25 | }
26 | else
27 | {
28 | if (char.IsWhiteSpace(text, iPos))
29 | {
30 | yield return text.Substring(iStart, iPos - iStart);
31 | iStart = -1;
32 | continue;
33 | }
34 | }
35 | iPos++;
36 | }
37 | if (iStart >= 0 && iStart < iPos)
38 | yield return text.Substring(iStart, iPos - iStart);
39 | }
40 | //=========================================================================================
41 | /// Разбить текст на строки.
42 | internal static List SplitTextToLines(string text)
43 | {
44 | List lines = new List();
45 |
46 | int i1 = 0, i2 = 0;
47 | while (i2 < text.Length)
48 | {
49 | char c = text[i2];
50 | if (c == '\r' || c == '\n')
51 | {
52 | string sLine = text.Substring(i1, i2 - i1);
53 | lines.Add(sLine);
54 | i1 = i2 + 1;
55 | if (c == '\r' && i1 < text.Length && text[i1] == '\n')
56 | i1++;
57 | i2 = i1;
58 | }
59 | else
60 | i2++;
61 | }
62 | if (i1 < text.Length)
63 | {
64 | string sLine = text.Substring(i1);
65 | lines.Add(sLine);
66 | }
67 | else if (i2 == i1)
68 | lines.Add(string.Empty);
69 | return lines;
70 | }
71 | //=========================================================================================
72 | /// Разбить текст на строки.
73 | internal static IEnumerable GetLinesFromText(string text)
74 | {
75 | int i1 = 0, i2 = 0;
76 | while (i2 < text.Length)
77 | {
78 | char c = text[i2];
79 | if (c == '\r' || c == '\n')
80 | {
81 | int iLen = i2 - i1;
82 | if (i1 >= 0 && iLen >= 0 && i1 + iLen < text.Length)
83 | {
84 | string sLine;
85 | try
86 | {
87 | sLine = text.Substring(i1, iLen);
88 | }
89 | catch (Exception ex)
90 | {
91 | ex.Data.Add("RawText", text);
92 | ex.Data.Add("start", i1);
93 | ex.Data.Add("len", iLen);
94 | throw;
95 | }
96 | yield return sLine;
97 | }
98 | i1 = i2 + 1;
99 | if (c == '\r' && i1 < text.Length && text[i1] == '\n')
100 | i1++;
101 | i2 = i1;
102 | }
103 | else
104 | i2++;
105 | }
106 | if (i1 < text.Length)
107 | {
108 | string sLine = text.Substring(i1);
109 | yield return sLine;
110 | }
111 | else if (i2 == i1)
112 | yield return string.Empty;
113 | }
114 | //=========================================================================================
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/IntelliSense/AutoCompleteTests.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using System.Windows.Forms;
3 | using Moq;
4 | using NUnit.Framework;
5 | using SA.CodeView;
6 | using SA.CodeView.IntelliSense;
7 | using Tests.IntelliSense.BLL;
8 |
9 | namespace Tests.IntelliSense
10 | {
11 | [TestFixture]
12 | public class AutoCompleteTests
13 | {
14 | readonly CodeViewer Viewer;
15 | /// Substitution variants were displayed.
16 | bool VariantsWereShown;
17 | //=========================================================================================
18 | public AutoCompleteTests()
19 | {
20 | this.Viewer = new CodeViewer();
21 | this.Viewer.ReadOnly = false;
22 | this.Viewer.Language = PredefinedLanguage.MsSql;
23 |
24 | var oTestProvider = new TestDbInfoProvider();
25 | var oSuggestionBuilder = new EditQueryRegExBuilder(Viewer, oTestProvider);
26 | oSuggestionBuilder.DefaultSchema = "Schema_Second";
27 |
28 | //Create mock
29 | var oMock = new Mock(MockBehavior.Default);
30 | //Mock variants list drawing
31 | oMock.Setup(x => x.ShowVariants(It.IsAny())).Callback(() => this.VariantsWereShown = true);
32 | oMock.Setup(x => x.HideVariants()).Callback(() => this.VariantsWereShown = false);
33 | oMock.Setup(x => x.IsVariantsVisible).Returns(() => this.VariantsWereShown);
34 |
35 | Viewer.CodeCompletor = oMock.Object;
36 | this.Viewer.UseSuggestionRules(oSuggestionBuilder);
37 | }
38 | //=========================================================================================
39 | [SetUp]
40 | public void SetUp()
41 | {
42 | this.VariantsWereShown = false;
43 | }
44 | //=========================================================================================
45 | /// Autocomplete when there is only one possible variant
46 | [Test]
47 | public void AutoCompete_with_one_variant()
48 | {
49 | Viewer.Text = "Select app from Schema_Second.Fruits \t ";
50 | Viewer.Caret.MoveToPos(0, "Select app".Length, true);
51 |
52 | Viewer.CodeCompletor.AutoComplete();
53 | Assert.AreEqual("Select Apple from Schema_Second.Fruits \t ", Viewer.Text);
54 | }
55 | //=========================================================================================
56 | /// Auto complete when there are many variants.
57 | [Test]
58 | public void AutoCompete_with_many_variants()
59 | {
60 | string sText = "Select from Schema_ \t ";
61 | this.Viewer.Text = sText;
62 | this.Viewer.Caret.MoveToPos(0, "Select from Schema_".Length, true);
63 |
64 | this.Viewer.CodeCompletor.AutoComplete();
65 | //Text shoulb be the same as before
66 | Assert.AreEqual(sText, this.Viewer.Text);
67 | //variant list should be displayed
68 | Assert.IsTrue(this.VariantsWereShown);
69 | }
70 | //=========================================================================================
71 | /// Auto complete after inner join.
72 | [Test]
73 | public void AutoComplete_with_many_variants_after_join()
74 | {
75 | string sText = "Select lemon from Schema_Second.Fruits\r\ninner join ";
76 | this.Viewer.Text = sText;
77 | this.Viewer.Caret.MoveDocEnd(true);
78 |
79 | this.Viewer.CodeCompletor.AutoComplete();
80 | //Text shoulb be the same as before
81 | Assert.AreEqual(sText, this.Viewer.Text);
82 | //variant list should be displayed
83 | Assert.IsTrue(this.VariantsWereShown);
84 | }
85 | //=========================================================================================
86 | [Test]
87 | public void AutoComplete_table_name()
88 | {
89 | //Arrange
90 | this.Viewer.Text = "Select * from f";
91 | this.Viewer.Caret.MoveDocEnd(true);
92 |
93 | //Act
94 | this.Viewer.CodeCompletor.AutoComplete();
95 |
96 | //Assert
97 | Assert.AreEqual(this.Viewer.Text, "Select * from Fruits");
98 | Assert.IsFalse(this.VariantsWereShown);
99 | }
100 | //=========================================================================================
101 | /// Bug fix test: previous word (select) was erased after autocompletion.
102 | [Test]
103 | public void Select_Variant_From_List()
104 | {
105 | this.Viewer.Text = "Select";
106 | this.Viewer.Caret.MoveDocEnd(true);
107 | this.Viewer.Body.ProcessChar(' ');
108 | this.Viewer.Body.ProcessKey(new KeyEventArgs(Keys.Down));
109 | this.Viewer.Body.ProcessKey(new KeyEventArgs(Keys.Down));
110 | this.Viewer.Body.ProcessKey(new KeyEventArgs(Keys.Enter));
111 | Assert.AreEqual("Select Vitamins", Viewer.Text);
112 | }
113 | //=========================================================================================
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/SA.CodeView/Utils/WordFinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SA.CodeView.Utils
4 | {
5 | /// Помогает выделять слова в строке.
6 | static class WordFinder
7 | {
8 | enum LetterType { WhiteSpace, LetterOrDigit, Separator, Punctuation }
9 | //=========================================================================================
10 | /// Найти начало следующего слова
11 | static public int GetNextWordStart(string line, int col)
12 | {
13 | LetterType type = GetLetterType(line[col]);
14 | if (type != LetterType.WhiteSpace)
15 | {
16 | while (col < line.Length &&
17 | GetLetterType(line[col]) == type)
18 | col++;
19 | }
20 | while (col < line.Length &&
21 | GetLetterType(line[col]) == LetterType.WhiteSpace)
22 | col++;
23 | return col;
24 | }
25 | //=========================================================================================
26 | /// Найти начало текущего слова
27 | static public int GetWordStart(string line, int col)
28 | {
29 | while (col > 0 &&
30 | GetLetterType(line[col - 1]) == LetterType.WhiteSpace)
31 | col--;
32 |
33 | if (col > 0)
34 | {
35 | LetterType type = GetLetterType(line[col - 1]);
36 | while (col > 0 &&
37 | GetLetterType(line[col - 1]) == type)
38 | col--;
39 | }
40 | return col;
41 | }
42 | //=========================================================================================
43 | /// Найти начало и конец слова, определенного позицией col.
44 | public static int[] GetWord(string line, int chr, int tabsize)
45 | {
46 | int iStart, iEnd;
47 | if (chr >= line.Length)
48 | {
49 | //Последнее слово
50 | line = line.TrimEnd();
51 | if (line.Length == 0)
52 | return new int[] { 0, 0 };
53 | LetterType letterType = GetLetterType(line[line.Length - 1]);
54 | iStart = GetFirstLetter(line, line.Length, letterType);
55 | iEnd = line.Length;
56 | }
57 | else if (chr == 0)
58 | {
59 | if (line.Length == 0)
60 | return new int[] { 0, 0 };
61 | LetterType letterType = GetLetterType(line[0]);
62 |
63 | iStart = 0;
64 | if (letterType == LetterType.WhiteSpace)
65 | iEnd = line.Length - line.TrimStart().Length;
66 | else
67 | iEnd = GetLastLetter(line, 0, letterType);
68 | }
69 | else if (!char.IsWhiteSpace(line, chr))
70 | {
71 | //Текущее слово
72 | LetterType letterType = GetLetterType(line[chr]);
73 | iStart = GetFirstLetter(line, chr, letterType);
74 | iEnd = GetLastLetter(line, chr, letterType);
75 | }
76 | else if (!char.IsWhiteSpace(line, chr - 1))
77 | {
78 | //Предыдущее слово
79 | LetterType letterType = GetLetterType(line[chr - 1]);
80 | iStart = GetFirstLetter(line, chr - 1, letterType);
81 | iEnd = chr;
82 | }
83 | else
84 | {
85 | //Текущий набор пробелов
86 | LetterType letterType = LetterType.WhiteSpace;
87 | iStart = GetFirstLetter(line, chr, letterType);
88 | iEnd = GetLastLetter(line, chr, letterType);
89 | }
90 | iStart = TextCaret.GetCol(line, iStart, tabsize);
91 | iEnd = TextCaret.GetCol(line, iEnd, tabsize);
92 |
93 | return new int[] { iStart, iEnd };
94 | }
95 | //=========================================================================================
96 | /// Найти позицию первого символа с указанным типом.
97 | static int GetFirstLetter(string line, int chr, LetterType letterType)
98 | {
99 | while (chr > 0 && GetLetterType(line[chr - 1]) == letterType)
100 | chr--;
101 | return chr;
102 | }
103 | //=========================================================================================
104 | /// Найти позицию последнего символа с указанным типом + 1.
105 | static int GetLastLetter(string line, int chr, LetterType letterType)
106 | {
107 | while (chr < line.Length && GetLetterType(line[chr]) == letterType)
108 | chr++;
109 | return chr;
110 | }
111 | //=========================================================================================
112 | /// Определить тип символа
113 | static LetterType GetLetterType(char c)
114 | {
115 | if (char.IsLetterOrDigit(c) || c == '_')
116 | return LetterType.LetterOrDigit;
117 | if (char.IsWhiteSpace(c))
118 | return LetterType.WhiteSpace;
119 | if (char.IsSeparator(c))
120 | return LetterType.Separator;
121 | if (char.IsPunctuation(c))
122 | return LetterType.Punctuation;
123 | if (char.IsControl(c))
124 | return LetterType.WhiteSpace;
125 | return LetterType.Punctuation;
126 | }
127 | //=========================================================================================
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/Document.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Drawing;
5 | using SA.CodeView.Utils;
6 |
7 | namespace SA.CodeView
8 | {
9 | public class Document : IEnumerable
10 | {
11 | readonly List Lines;
12 | //=========================================================================================
13 | public int Count
14 | {
15 | get
16 | {
17 | if (this.Lines == null)
18 | return 0;
19 |
20 | return this.Lines.Count;
21 | }
22 | }
23 | //=========================================================================================
24 | public Document()
25 | {
26 | this.Lines = new List();
27 | this.Lines.Add(new DocumentLine(""));
28 | }
29 | //=========================================================================================
30 | internal void SetText(string text)
31 | {
32 | this.Lines.Clear();
33 | foreach (string sLine in TextSplitter.GetLinesFromText(text))
34 | this.Lines.Add(new DocumentLine(sLine));
35 | }
36 | //=========================================================================================
37 | public DocumentLine this[int index]
38 | {
39 | get { return this.Lines[index]; }
40 | }
41 | //=========================================================================================
42 | internal void Insert(int index, string text)
43 | {
44 | this.Lines.Insert(index, new DocumentLine(text));
45 | }
46 | //=========================================================================================
47 | internal void RemoveAt(int index)
48 | {
49 | this.Lines.RemoveAt(index);
50 | }
51 | //=========================================================================================
52 | internal void RemoveRange(int index, int count)
53 | {
54 | this.Lines.RemoveRange(index, count);
55 | }
56 | //=========================================================================================
57 | internal void InsertRange(int index, List lines)
58 | {
59 | foreach (string sLine in lines)
60 | this.Lines.Insert(index++, new DocumentLine(sLine));
61 | }
62 | //=========================================================================================
63 | public IEnumerator GetEnumerator()
64 | {
65 | return this.Lines.GetEnumerator();
66 | }
67 | //=========================================================================================
68 | internal string GetText(TextPoint start, TextPoint end)
69 | {
70 | if (start > end)
71 | {
72 | TextPoint temp = start;
73 | start = end;
74 | end = temp;
75 | }
76 | if (start.Line == end.Line)
77 | return this.Lines[start.Line].Text.Substring(start.Char, end.Char - start.Char);
78 | else
79 | {
80 | System.Text.StringBuilder sb = new System.Text.StringBuilder();
81 |
82 | string sLine = this.Lines[start.Line].Text;
83 | sb.AppendLine(sLine.Substring(start.Char, sLine.Length - start.Char));
84 |
85 | for (int i = start.Line + 1; i < end.Line; i++)
86 | sb.AppendLine(this.Lines[i].Text);
87 |
88 | sb.Append(this.Lines[end.Line].Text.Substring(0, end.Char));
89 |
90 | return sb.ToString();
91 | }
92 | }
93 | //=========================================================================================
94 | internal string GetText(int startLine, int startChar, int endLine, int endChar)
95 | {
96 | var start = new TextPoint { Line = startLine, Char = startChar };
97 | var end = new TextPoint { Line = endLine, Char = endChar };
98 | return GetText(start, end);
99 | }
100 | //=========================================================================================
101 | }
102 | //#############################################################################################
103 | /// Specifies extra properties for text line in document.
104 | public class DocumentLine : IDisposable
105 | {
106 | public string Text;
107 | public Brush BackBrush;
108 | //=========================================================================================
109 | int _ImageIndex;
110 | public int ImageIndex
111 | {
112 | get { return _ImageIndex; }
113 | set { this._ImageIndex = value; }
114 | }
115 | //=========================================================================================
116 | internal DocumentLine(string text)
117 | {
118 | this.Text = text;
119 | this._ImageIndex = -1;
120 | }
121 | //=========================================================================================
122 | public void Dispose()
123 | {
124 | if (this.BackBrush == null)
125 | return;
126 |
127 | this.BackBrush.Dispose();
128 | }
129 | //=========================================================================================
130 | public override string ToString() => Text;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/Visual/IntellisenseForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace SA.CodeView.IntelliSense
2 | {
3 | partial class IntellisenseForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.components = new System.ComponentModel.Container();
32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IntellisenseForm));
33 | System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem("FROM", 2);
34 | System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("SELECT", 1);
35 | System.Windows.Forms.ListViewItem listViewItem3 = new System.Windows.Forms.ListViewItem("WHERE", 0);
36 | System.Windows.Forms.ListViewItem listViewItem4 = new System.Windows.Forms.ListViewItem("UNION", 3);
37 | this.imageList = new System.Windows.Forms.ImageList(this.components);
38 | this.listItems = new SA.CodeView.IntelliSense.IntelliSenseListView();
39 | this.columnHeader1 = new System.Windows.Forms.ColumnHeader();
40 | this.SuspendLayout();
41 | //
42 | // imageList
43 | //
44 | this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream")));
45 | this.imageList.TransparentColor = System.Drawing.Color.Transparent;
46 | this.imageList.Images.SetKeyName(0, "db.bmp");
47 | this.imageList.Images.SetKeyName(1, "schema.bmp");
48 | this.imageList.Images.SetKeyName(2, "table.bmp");
49 | this.imageList.Images.SetKeyName(3, "column.bmp");
50 | //
51 | // listItems
52 | //
53 | this.listItems.Alignment = System.Windows.Forms.ListViewAlignment.Left;
54 | this.listItems.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
55 | | System.Windows.Forms.AnchorStyles.Left)
56 | | System.Windows.Forms.AnchorStyles.Right)));
57 | this.listItems.BorderStyle = System.Windows.Forms.BorderStyle.None;
58 | this.listItems.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
59 | this.columnHeader1});
60 | this.listItems.FullRowSelect = true;
61 | this.listItems.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
62 | this.listItems.HideSelection = false;
63 | this.listItems.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
64 | listViewItem1,
65 | listViewItem2,
66 | listViewItem3,
67 | listViewItem4});
68 | this.listItems.Location = new System.Drawing.Point(0, 0);
69 | this.listItems.Margin = new System.Windows.Forms.Padding(2);
70 | this.listItems.MultiSelect = false;
71 | this.listItems.Name = "listItems";
72 | this.listItems.OwnerDraw = true;
73 | this.listItems.Size = new System.Drawing.Size(246, 181);
74 | this.listItems.SmallImageList = this.imageList;
75 | this.listItems.TabIndex = 6;
76 | this.listItems.UseCompatibleStateImageBehavior = false;
77 | this.listItems.View = System.Windows.Forms.View.Details;
78 | //
79 | // columnHeader1
80 | //
81 | this.columnHeader1.Width = 115;
82 | //
83 | // IntellisenseForm
84 | //
85 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
86 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
87 | this.BackColor = System.Drawing.Color.Silver;
88 | this.ClientSize = new System.Drawing.Size(246, 181);
89 | this.ControlBox = false;
90 | this.Controls.Add(this.listItems);
91 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
92 | this.MaximizeBox = false;
93 | this.MinimizeBox = false;
94 | this.Name = "IntellisenseForm";
95 | this.ShowIcon = false;
96 | this.ShowInTaskbar = false;
97 | this.Resize += new System.EventHandler(this.IntellisenseForm_Resize);
98 | this.ResizeEnd += new System.EventHandler(this.IntellisenseForm_ResizeEnd);
99 | this.ResumeLayout(false);
100 |
101 | }
102 |
103 | #endregion
104 |
105 | private System.Windows.Forms.ImageList imageList;
106 | private System.Windows.Forms.ColumnHeader columnHeader1;
107 | internal IntelliSenseListView listItems;
108 |
109 | }
110 | }
--------------------------------------------------------------------------------
/SA.CodeView.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio 2012
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SA.CodeView", "SA.CodeView\SA.CodeView.csproj", "{BFD6E02B-0B66-4895-BC2A-980664C7D21B}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SA.CodeView.Tests", "SA.CodeView.Tests\SA.CodeView.Tests.csproj", "{8C265740-C969-4FAB-9518-7234317FCEF2}"
6 | EndProject
7 | Global
8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
9 | Debug|Any CPU = Debug|Any CPU
10 | Debug|Mixed Platforms = Debug|Mixed Platforms
11 | Debug|Win32 = Debug|Win32
12 | Release|Any CPU = Release|Any CPU
13 | Release|Mixed Platforms = Release|Mixed Platforms
14 | Release|Win32 = Release|Win32
15 | StartUnitTests|Any CPU = StartUnitTests|Any CPU
16 | StartUnitTests|Mixed Platforms = StartUnitTests|Mixed Platforms
17 | StartUnitTests|Win32 = StartUnitTests|Win32
18 | TimeLimited|Any CPU = TimeLimited|Any CPU
19 | TimeLimited|Mixed Platforms = TimeLimited|Mixed Platforms
20 | TimeLimited|Win32 = TimeLimited|Win32
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
26 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
27 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Debug|Win32.ActiveCfg = Debug|Any CPU
28 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
31 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
32 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.Release|Win32.ActiveCfg = Release|Any CPU
33 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.StartUnitTests|Any CPU.ActiveCfg = TestDebug|Any CPU
34 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.StartUnitTests|Any CPU.Build.0 = TestDebug|Any CPU
35 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.StartUnitTests|Mixed Platforms.ActiveCfg = TestDebug|Any CPU
36 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.StartUnitTests|Mixed Platforms.Build.0 = TestDebug|Any CPU
37 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.StartUnitTests|Win32.ActiveCfg = TestDebug|Any CPU
38 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.TimeLimited|Any CPU.ActiveCfg = TimeLimited|Any CPU
39 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.TimeLimited|Any CPU.Build.0 = TimeLimited|Any CPU
40 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.TimeLimited|Mixed Platforms.ActiveCfg = TimeLimited|Any CPU
41 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.TimeLimited|Mixed Platforms.Build.0 = TimeLimited|Any CPU
42 | {BFD6E02B-0B66-4895-BC2A-980664C7D21B}.TimeLimited|Win32.ActiveCfg = TimeLimited|Any CPU
43 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
46 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
47 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Debug|Win32.ActiveCfg = Debug|Any CPU
48 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
51 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
52 | {8C265740-C969-4FAB-9518-7234317FCEF2}.Release|Win32.ActiveCfg = Release|Any CPU
53 | {8C265740-C969-4FAB-9518-7234317FCEF2}.StartUnitTests|Any CPU.ActiveCfg = TestDebug|Any CPU
54 | {8C265740-C969-4FAB-9518-7234317FCEF2}.StartUnitTests|Any CPU.Build.0 = TestDebug|Any CPU
55 | {8C265740-C969-4FAB-9518-7234317FCEF2}.StartUnitTests|Mixed Platforms.ActiveCfg = TestDebug|Any CPU
56 | {8C265740-C969-4FAB-9518-7234317FCEF2}.StartUnitTests|Mixed Platforms.Build.0 = TestDebug|Any CPU
57 | {8C265740-C969-4FAB-9518-7234317FCEF2}.StartUnitTests|Win32.ActiveCfg = TestDebug|Any CPU
58 | {8C265740-C969-4FAB-9518-7234317FCEF2}.TimeLimited|Any CPU.ActiveCfg = TimeLimited|Any CPU
59 | {8C265740-C969-4FAB-9518-7234317FCEF2}.TimeLimited|Any CPU.Build.0 = TimeLimited|Any CPU
60 | {8C265740-C969-4FAB-9518-7234317FCEF2}.TimeLimited|Mixed Platforms.ActiveCfg = TimeLimited|Any CPU
61 | {8C265740-C969-4FAB-9518-7234317FCEF2}.TimeLimited|Mixed Platforms.Build.0 = TimeLimited|Any CPU
62 | {8C265740-C969-4FAB-9518-7234317FCEF2}.TimeLimited|Win32.ActiveCfg = TimeLimited|Any CPU
63 | EndGlobalSection
64 | GlobalSection(SolutionProperties) = preSolution
65 | HideSolutionNode = FALSE
66 | EndGlobalSection
67 | EndGlobal
68 |
--------------------------------------------------------------------------------
/SA.CodeView/Parsing/StateScanner.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.Parsing
5 | {
6 | [Flags]
7 | enum CharType { Letters = 0x01, Numbers = 0x02, AnyNonSpaces = 0x04, Unknown = 0x08 }
8 | //#############################################################################################
9 | /// Разбивает входной поток на токены. Работает на основе конечного автомата.
10 | class StateScanner
11 | {
12 | public readonly List Errors;
13 | readonly ScannerSpecification Specification;
14 | StateScannerState CurrentState;
15 | IBufferReader _Reader;
16 | /// Последний считанный токен.
17 | Token LastToken;
18 | /// Вернуть тот же токен, что и в предыдущий раз.
19 | bool ReturnPreviousToken;
20 | /// Если последний считанный сканером токен имеет ограничители, то это длина НАЧАЛЬНОГО ограничителя; иначе 0
21 | internal int StartLimiterLength;
22 | /// Если последний считанный сканером токен имеет ограничители, то это длина КОНЕЧНОГО ограничителя; иначе 0
23 | internal int EndLimiterLength;
24 | internal int TabSize;
25 | //=========================================================================================
26 | public StateScanner(ScannerSpecification specification, int tabsize)
27 | {
28 | this.Errors = new List();
29 | this.Specification = specification;
30 | this._Reader = new BufferReader(tabsize);
31 | this.TabSize = tabsize;
32 | }
33 | //=========================================================================================
34 | /// Задать строку для нового разбора на токены.
35 | public void SetSource(string text)
36 | {
37 | this.CurrentState = null;
38 | this.ReturnPreviousToken = false;
39 | this.Errors.Clear();
40 | this._Reader.SetSource(text);
41 | }
42 | //=========================================================================================
43 | /// Получить очередной токен.
44 | public Token ReadNextToken()
45 | {
46 | if (this.ReturnPreviousToken && this.LastToken != null)
47 | {
48 | this.ReturnPreviousToken = false;
49 | return this.LastToken;
50 | }
51 |
52 | ///Пропускаем все пробелы
53 | char cChar;
54 | do
55 | {
56 | cChar = this._Reader.ReadChar();
57 | if (cChar == '\0')
58 | return null;
59 | }
60 | while (char.IsWhiteSpace(cChar));
61 |
62 | ///Становимся на начальное состояние
63 | this.CurrentState = this.Specification.StartState;
64 | ///Засекаем начало токена
65 | int iStart = this._Reader.Position - 1;
66 | var pointStart = this._Reader.PreviousPoint;
67 |
68 | while (true)
69 | {
70 | ///Ищем следующее состояние на основании текущего символа
71 | var oNewState = this.CurrentState.GetNextState(cChar);
72 | ///Если мы перешли в состоянии ошибки, генерим ошибку
73 | if (oNewState == this.Specification.FailState)
74 | {
75 | this.Errors.Add(this.CurrentState.GetExpectationToString());
76 | }
77 | ///Если пора выходить
78 | if (oNewState == this.Specification.EndState)
79 | {
80 | var oToken = this.GetToken(iStart, pointStart, this._Reader.Position - 1, this._Reader.PreviousPoint);
81 | ///Возвращаемся на символ назад, чтобы в следующий раз начать с правильной позиции
82 | this._Reader.BackToChar();
83 | return oToken;
84 | }
85 | if (oNewState == null)
86 | throw new NullReferenceException(this.CurrentState.Name);
87 | this.CurrentState = oNewState;
88 |
89 | ///Читаем новый символ
90 | cChar = this._Reader.ReadChar();
91 | if (cChar == '\0')
92 | return this.GetToken(iStart, pointStart, this._Reader.Position, this._Reader.Point);
93 | }
94 | }
95 | //=========================================================================================
96 | /// Сформировать новый токен.
97 | Token GetToken(int start, TextPoint pointStart, int end, TextPoint pointEnd)
98 | {
99 | if (start >= end)
100 | return null;
101 |
102 | ///Определяем тип токена
103 | string sTokenType = (this.CurrentState != null) ? this.CurrentState.ResultTokenName : null;
104 |
105 | ///Указываем ограничители для текущего токена
106 | this.StartLimiterLength = this.CurrentState.StartLimiterLength;
107 | this.EndLimiterLength = this.CurrentState.EndLimiterLength;
108 |
109 | this.LastToken = new Token(
110 | sTokenType,
111 | this._Reader.GetSubstring(start, end - start),
112 | pointStart,
113 | pointEnd,
114 | null);
115 | return this.LastToken;
116 | }
117 | //=========================================================================================
118 | /// Вернуться на один токен назад.
119 | internal void BackToToken()
120 | {
121 | this.ReturnPreviousToken = true;
122 | }
123 | //=========================================================================================
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Parsing/MsSqlParsingTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using SA.CodeView.Languages;
3 | using SA.CodeView.Parsing;
4 |
5 | namespace Tests.Parsing
6 | {
7 | /// Проверяем качество разбора MS SQL Server скриптов.
8 | [TestFixture]
9 | public class MsSqlParsingTests
10 | {
11 | readonly StateParser Parser;
12 | //=========================================================================================
13 | public MsSqlParsingTests()
14 | {
15 | this.Parser = new StateParser(new MsSqlSyntaxSettings(), 4);
16 | }
17 | //=========================================================================================
18 | void ReadTokenWithStyle(string style, string text)
19 | {
20 | var oToken = this.Parser.GetNextToken();
21 | if (this.Parser.Errors.Count > 0)
22 | Assert.Fail(this.Parser.Errors[0]);
23 | Assert.That(oToken.Text, Is.EqualTo(text));
24 | Assert.AreEqual(oToken.Style.Name, style);
25 | }
26 | //=========================================================================================
27 | /// Простая конструкция select ... from system table.
28 | [Test]
29 | public void SimpleSelect()
30 | {
31 | this.Parser.SetSource(@"
32 | Select 1
33 | FROM
34 | sysobjects");
35 |
36 | this.ReadTokenWithStyle("Keywords1", "Select");
37 | this.ReadTokenWithStyle("Numbers", "1");
38 | this.ReadTokenWithStyle("Keywords1", "FROM");
39 | this.ReadTokenWithStyle("SysTables", "sysobjects");
40 | var oToken = this.Parser.GetNextToken();
41 | Assert.IsNull(oToken);
42 | }
43 | //=========================================================================================
44 | /// Многострочные комментарии.
45 | [Test]
46 | public void MultiLineComments()
47 | {
48 | this.Parser.SetSource(@"
49 | /** x
50 | **/
51 | -- /* asd
52 | select");
53 |
54 | this.ReadTokenWithStyle("MultiLine Comment", "/** x");
55 | this.ReadTokenWithStyle("MultiLine Comment", "**/");
56 | this.ReadTokenWithStyle("SingleLine Comment", "-- /* asd");
57 | this.ReadTokenWithStyle("Keywords1", "select");
58 | var oToken = this.Parser.GetNextToken();
59 | Assert.IsNull(oToken);
60 | }
61 | //=========================================================================================
62 | /// Строковая константа в одинарных ковычках с использованием escape-символов.
63 | [Test]
64 | public void StringConst()
65 | {
66 | this.Parser.SetSource(@"
67 | select 'xx''xx'
68 | ");
69 |
70 | this.ReadTokenWithStyle("Keywords1", "select");
71 | this.ReadTokenWithStyle("String", "'xx''xx'");
72 | var oToken = this.Parser.GetNextToken();
73 | Assert.IsNull(oToken);
74 | }
75 | //=========================================================================================
76 | /// Строковая константа в одинарных ковычках с префиксом N.
77 | [Test]
78 | public void StringConstUnicode()
79 | {
80 | this.Parser.SetSource(@"select N'xxxx', n'ab c'");
81 | this.Parser.GetNextToken();
82 | this.ReadTokenWithStyle("String", "N'xxxx'");
83 | this.Parser.GetNextToken();
84 | this.ReadTokenWithStyle("String", "n'ab c'");
85 | }
86 | //=========================================================================================
87 | /// Идентификатор в квадратных скобках.
88 | [Test]
89 | public void Id_In_Square_Brackets()
90 | {
91 | this.Parser.SetSource("select [T 1]");
92 | this.Parser.GetNextToken();
93 | this.ReadTokenWithStyle("Normal", "[T 1]");
94 | }
95 | //=========================================================================================
96 | /// Использование разделителей в однострочных комментариях. Тест на исправление ошибки.
97 | [Test]
98 | public void Separators_And_Comments()
99 | {
100 | this.Parser.SetSource("--select dbo.t1\r\nselect");
101 | this.ReadTokenWithStyle("SingleLine Comment", "--select dbo.t1");
102 | }
103 | //=========================================================================================
104 | /// Однострочный комментарии идут после операторов.Тест на исправление ошибки.
105 | [Test]
106 | public void Comments_After_Separator()
107 | {
108 | this.Parser.SetSource("select (--xxxxxxx\r\n 1)");
109 | this.Parser.GetNextToken();
110 | this.ReadTokenWithStyle("Operators", "(");
111 | this.ReadTokenWithStyle("SingleLine Comment", "--xxxxxxx");
112 | }
113 | //=========================================================================================
114 | /// Ключевые слова, начинающиеся на N, должны обрабатываться корректно.
115 | [Test]
116 | public void Keywords_With_Letter_N_Must_Be_Processed_Correctly()
117 | {
118 | this.Parser.SetSource("nocount on");
119 | //this.ReadTokenWithStyle("Keywords1", "set");
120 | this.ReadTokenWithStyle("Keywords1", "nocount");
121 | this.ReadTokenWithStyle("Keywords1", "on");
122 | }
123 | //=========================================================================================
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/Parsing/XmlParsingTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using SA.CodeView.Languages;
3 | using SA.CodeView.Parsing;
4 |
5 | namespace Tests.Parsing
6 | {
7 | [TestFixture]
8 | public class XmlParsingTests
9 | {
10 | readonly StateParser Parser;
11 | //=========================================================================================
12 | public XmlParsingTests()
13 | {
14 | this.Parser = new StateParser(new XmlSyntaxSettings(), 4);
15 | }
16 | //=========================================================================================
17 | void ReadTokenWithStyle(string style, string text)
18 | {
19 | var oToken = this.Parser.GetNextToken();
20 | if (this.Parser.Errors.Count > 0)
21 | Assert.Fail(this.Parser.Errors[0]);
22 | Assert.That(oToken.Text, Is.EqualTo(text));
23 | Assert.AreEqual(oToken.Style.Name, style);
24 | }
25 | //=========================================================================================
26 | void ReadTokenWithStyle(string style, string text, int startLine, int startCol, int startChar, int endLine, int endCol, int endChar)
27 | {
28 | var oToken = this.Parser.GetNextToken();
29 | if (this.Parser.Errors.Count > 0)
30 | Assert.Fail(this.Parser.Errors[0]);
31 | Assert.That(oToken.Text, Is.EqualTo(text));
32 | Assert.AreEqual(oToken.Style.Name, style);
33 | Assert.That(oToken.Start.ToString(), Is.EqualTo(string.Format("Ln:{0}, col:{1}, ch:{2}", startLine, startCol, startChar)));
34 | Assert.That(oToken.End.ToString(), Is.EqualTo(string.Format("Ln:{0}, col:{1}, ch:{2}", endLine, endCol, endChar)));
35 | }
36 | //=========================================================================================
37 | /// Проверяем, как определяется указанный в правиле стиль.
38 | [Test]
39 | public void Tag_Attribute_Value()
40 | {
41 | this.Parser.SetSource("");
42 |
43 | this.ReadTokenWithStyle("separator", "<");
44 | this.ReadTokenWithStyle("tagName", "assembly");
45 | this.ReadTokenWithStyle("attribute", "style");
46 | this.ReadTokenWithStyle("separator", "=");
47 | this.ReadTokenWithStyle("Normal", "\"");
48 | this.ReadTokenWithStyle("attributeValue", "simple style");
49 | this.ReadTokenWithStyle("Normal", "\"");
50 | this.ReadTokenWithStyle("attribute", "x");
51 | this.ReadTokenWithStyle("separator", "=");
52 | this.ReadTokenWithStyle("Normal", "\"");
53 | this.ReadTokenWithStyle("attributeValue", "y");
54 | this.ReadTokenWithStyle("Normal", "\"");
55 | this.ReadTokenWithStyle("separator", ">");
56 | var oToken = this.Parser.GetNextToken();
57 | Assert.IsNull(oToken);
58 | }
59 | //=========================================================================================
60 | /// Открывающий и закрывающий тег.
61 | [Test]
62 | public void Opening_And_Closing_Tags()
63 | {
64 | this.Parser.SetSource("");
65 |
66 | this.ReadTokenWithStyle("separator", "<");
67 | this.ReadTokenWithStyle("tagName", "Tag");
68 | this.ReadTokenWithStyle("separator", ">");
69 | this.ReadTokenWithStyle("separator", "");
70 | this.ReadTokenWithStyle("tagName", "Tag");
71 | this.ReadTokenWithStyle("separator", ">");
72 | var oToken = this.Parser.GetNextToken();
73 | Assert.IsNull(oToken);
74 | }
75 | //=========================================================================================
76 | /// Комментарии в тексте без перевода строки.
77 | [Test]
78 | public void CommentsInLine()
79 | {
80 | this.Parser.SetSource("");
81 | this.ReadTokenWithStyle("separator", "", 0, 23, 23, 0, 26, 26);
84 | }
85 | //=========================================================================================
86 | /// Комментарии в мнострочном тексте.
87 | [Test]
88 | public void CommentsInText()
89 | {
90 | //this.Parser.SetSource("]]>");
91 | this.Parser.SetSource(@"
92 |
93 |
94 |
95 | ");
96 | this.Parser.GetNextToken();
97 | this.Parser.GetNextToken();
98 | this.Parser.GetNextToken();
99 | this.ReadTokenWithStyle("separator", "", 2, 27, 24, 2, 30, 27);
102 | }
103 | //=========================================================================================
104 | /// Проверяем, как читается CDATA.
105 | [Test]
106 | public void ReadCData()
107 | {
108 | this.Parser.SetSource("]]>");
109 | this.ReadTokenWithStyle("separator", "");
111 | this.ReadTokenWithStyle("separator", "]]>");
112 | }
113 | //=========================================================================================
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/SA.CodeView/Languages/XmlSyntaxSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 | using SA.CodeView.ParsingOnElements;
4 | using SA.CodeView.Parsing;
5 |
6 | namespace SA.CodeView.Languages
7 | {
8 | class XmlSyntaxSettings : SyntaxSettings
9 | {
10 | //=========================================================================================
11 | public XmlSyntaxSettings()
12 | {
13 | this.Operators = new char[] { };
14 | }
15 | //=========================================================================================
16 | protected override Dictionary CreateTextStyles()
17 | {
18 | var styles = base.CreateTextStyles();
19 | this.AddStyle(styles, new TextStyle("separator", Color.Blue));
20 | this.AddStyle(styles, new TextStyle("tagName", Color.Brown));
21 | this.AddStyle(styles, new TextStyle("attribute", Color.Red));
22 | this.AddStyle(styles, new TextStyle("attributeValue", Color.Blue));
23 | this.AddStyle(styles, new TextStyle("quotes", Color.Red));
24 | this.AddStyle(styles, new TextStyle("comments", Color.Green));
25 | this.AddStyle(styles, new TextStyle("cdata", Color.Teal));
26 |
27 | return styles;
28 | }
29 | //=========================================================================================
30 | internal override ScannerSpecification CreateScannerSpecification()
31 | {
32 | var oSpec = new ScannerSpecification();
33 | oSpec.AddLiteral("letter", CharType.Letters, '_');
34 | oSpec.AddLiteral("digit", CharType.Numbers);
35 | oSpec.AddLiteral("lt", '<');
36 | oSpec.AddLiteral("gt", '>');
37 | oSpec.AddLiteral("sqBr1", '[');
38 | oSpec.AddLiteral("sqBr2", ']');
39 | oSpec.AddLiteral("slash", '/');
40 | oSpec.AddLiteral("quest", '?');
41 | oSpec.AddLiteral("excl", '!');
42 | oSpec.AddLiteral("minus", '-');
43 | oSpec.AddLiteral("eq", '=');
44 | oSpec.AddLiteral("doubleQuote", '"');
45 | oSpec.AddLiteral("c", 'C');
46 | oSpec.AddLiteral("d", 'D');
47 | oSpec.AddLiteral("a", 'A');
48 | oSpec.AddLiteral("t", 'T');
49 |
50 | oSpec.AddTokenDeclaration("id", "letter{letter|digit}");
51 | oSpec.AddTokenDeclaration("lt", "lt[slash|quest]");
52 | oSpec.AddTokenDeclaration("gt", "[slash|quest]gt");
53 | oSpec.AddTokenDeclaration("eq", "eq");
54 | oSpec.AddBoundedToken("attrValue", "doubleQuote", "doubleQuote", null, 1, 1);
55 | oSpec.AddBoundedToken("comment", "lt excl minus minus", "minus minus gt", null, 4, 3);
56 | oSpec.AddBoundedToken("cdata", "lt excl sqBr1 c d a t a sqBr1", "sqBr2 sqBr2 gt", null, 9, 3);
57 |
58 | return oSpec;
59 | }
60 | //=========================================================================================
61 | internal override ParserSpecification CreateParserSpecification(ScannerSpecification scannerSpecification)
62 | {
63 | var oSpec = new ParserSpecification();
64 | oSpec.AddRule("Tag", "lt?separator? id?tagName? {id?attribute? eq?separator? attrValue?attributeValue?} gt?separator?");
65 | oSpec.AddRule("Comment", "comment?comments?");
66 | oSpec.AddRule("Cdata", "cdata?cdata?");
67 | return oSpec;
68 | }
69 | //=========================================================================================
70 | internal override TextStyle GetStyleFor(Token token, string styleName)
71 | {
72 | if (token.TokenTypeName == "comment-start")
73 | return this.GetStyleByName("separator");
74 | if (token.TokenTypeName == "comment-end")
75 | return this.GetStyleByName("separator");
76 |
77 | if (token.TokenTypeName == "attrValue-start")
78 | return this.NormalTextStyle;
79 | if (token.TokenTypeName == "attrValue-end")
80 | return this.NormalTextStyle;
81 |
82 | if (token.TokenTypeName == "cdata-start")
83 | return this.GetStyleByName("separator");
84 | if (token.TokenTypeName == "cdata-end")
85 | return this.GetStyleByName("separator");
86 |
87 | return base.GetStyleFor(token, styleName);
88 | }
89 | //=========================================================================================
90 | protected override List CreateElements()
91 | {
92 | var elements = new List();
93 | TextStyle oBoundStyle = new TextStyle("Brackets", Color.Blue);
94 | {
95 | ///CDATA
96 | BoundedElement oBlock = new BoundedElement(new TextStyle("CDATA", Color.Gray), oBoundStyle, "");
97 | elements.Add(oBlock);
98 | }
99 | {
100 | ///комментарии
101 | BoundedElement oBlock = new BoundedElement(new TextStyle("Comment", Color.Green), oBoundStyle, "");
102 | elements.Add(oBlock);
103 | }
104 |
105 | {
106 | ///закрывающие теги
107 | BoundedElement oBlock = new BoundedElement(new TextStyle("Tag", Color.Black), oBoundStyle, "", ">");
108 | elements.Add(oBlock);
109 | }
110 |
111 | {
112 | ///Простые теги в угловых скобках
113 | BoundedElement oBlock = new BoundedElement(new TextStyle("Tag", Color.Black), oBoundStyle, "<", ">");
114 | elements.Add(oBlock);
115 | }
116 | return elements;
117 | }
118 | //=========================================================================================
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/SA.CodeView/Languages/CSharpSyntaxSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using SA.CodeView.ParsingOnElements;
5 | using System.Drawing;
6 | using SA.CodeView.Parsing;
7 |
8 | namespace SA.CodeView.Languages
9 | {
10 | class CSharpSyntaxSettings : SyntaxSettings
11 | {
12 | //=========================================================================================
13 | public CSharpSyntaxSettings()
14 | {
15 | this.Operators = new char[] { '=', '+', '-', '/', '*', '%', '>', '<', '&', '|', '^', '~', '(', ')', '[', ']', ',' };
16 | }
17 | //=========================================================================================
18 | protected override List CreateElements()
19 | {
20 | var elements = new List();
21 | return elements;
22 | }
23 | //=========================================================================================
24 | protected override Dictionary CreateTextStyles()
25 | {
26 | var styles = base.CreateTextStyles();
27 | this.AddStyle(styles, new TextStyle(S_OPERATORS, Color.Black));
28 | this.AddStyle(styles, new TextStyle(S_STRINGS, Color.Maroon));
29 | this.AddStyle(styles, new TextStyle(S_MULTI_COMMENT, Color.Green));
30 | this.AddStyle(styles, new TextStyle(S_SINGLE_COMMENT, Color.Green));
31 | this.AddStyle(styles, new TextStyle(S_IDENTIFIER, Color.Black));
32 | this.AddStyle(styles, new TextStyle(S_NUMBERS, Color.Black));
33 | this.AddStyle(styles, new TextStyle(S_KEYWORDS_1, Color.Blue, true));
34 | return styles;
35 | }
36 | //=========================================================================================
37 | internal override ScannerSpecification CreateScannerSpecification()
38 | {
39 | var oSpec = new ScannerSpecification();
40 | oSpec.AddLiteral("l", CharType.Letters, '_');
41 | oSpec.AddLiteral("d", CharType.Numbers);
42 | oSpec.AddLiteral("minus", '-');
43 | oSpec.AddLiteral("asterisk", '*');
44 | oSpec.AddLiteral("slash", '/');
45 | oSpec.AddLiteral("backSlash", '\\');
46 | oSpec.AddLiteral("operators", '=', '>', '<', ';', ',', '.', '+', ')', '(', '|', '&');
47 | oSpec.AddLiteral("singleQuote", '\'');
48 | oSpec.AddLiteral("doubleQuote", '"');
49 | oSpec.AddLiteral("caretReturn", '\n');
50 |
51 | oSpec.AddTokenDeclaration("id", "l{l|d}");
52 | oSpec.AddTokenDeclaration("number", "d{d}");
53 | oSpec.AddTokenDeclaration("operator", "(operators|minus)");
54 | oSpec.AddBoundedToken("charConst", "singleQuote", "singleQuote", "backSlash");
55 | oSpec.AddBoundedToken("comment1", "slash asterisk", "asterisk slash", null);
56 | oSpec.AddBoundedToken("comment2", "slash slash", "caretReturn", null);
57 | oSpec.AddBoundedToken("stringConst", "doubleQuote", "doubleQuote", "backSlash");
58 |
59 | return oSpec;
60 | }
61 | //=========================================================================================
62 | protected override void FillKeywordGroups(Dictionary dictionary)
63 | {
64 | base.FillKeywordGroups(dictionary);
65 | TextStyle oStyle;
66 |
67 | ///Ключевые слова первого эшелона
68 | oStyle = this.GetStyleByName(S_KEYWORDS_1);
69 | this.LoadKeywordsToGroup(dictionary, oStyle, @"
70 | abstract
71 | as
72 | base
73 | bool
74 |
75 | break
76 | byte
77 | case
78 | catch
79 |
80 | char
81 | checked
82 | class
83 | const
84 |
85 | continue
86 | decimal
87 | default
88 | delegate
89 |
90 | do
91 | double
92 | else
93 | enum
94 |
95 | event
96 | explicit
97 | extern
98 | false
99 |
100 | finally
101 | fixed
102 | float
103 | for
104 |
105 | foreach
106 | goto
107 | if
108 | implicit
109 |
110 | in
111 | int
112 | interface
113 |
114 | internal
115 | is
116 | lock
117 | long
118 |
119 | namespace
120 | new
121 | null
122 | object
123 |
124 | operator
125 | out
126 | override
127 |
128 | params
129 | private
130 | protected
131 | public
132 |
133 | readonly
134 | ref
135 | return
136 | sbyte
137 |
138 | sealed
139 | short
140 | sizeof
141 | stackalloc
142 |
143 | static
144 | string
145 | struct
146 | switch
147 |
148 | this
149 | throw
150 | true
151 | try
152 |
153 | typeof
154 | uint
155 | ulong
156 | unchecked
157 |
158 | unsafe
159 | ushort
160 | using
161 | virtual
162 |
163 | void
164 | volatile
165 | while
166 |
167 |
168 |
169 | add
170 | alias
171 | ascending
172 |
173 | descending
174 | dynamic
175 | from
176 |
177 | get
178 | global
179 | group
180 |
181 | into
182 | join
183 | let
184 |
185 | orderby
186 | partial
187 |
188 | remove
189 | select
190 | set
191 |
192 | value
193 | var
194 |
195 | where
196 | yield
197 | ");
198 | }
199 | //=========================================================================================
200 | internal override TextStyle GetStyleFor(Token token, string styleName)
201 | {
202 | if (token.TokenTypeName == "charConst")
203 | return this.TextStyles[S_STRINGS];
204 |
205 | return base.GetStyleFor(token, styleName);
206 | }
207 | //=========================================================================================
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/Visual/WinApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Runtime.InteropServices;
4 | using System.Windows.Forms;
5 |
6 | namespace SA.CodeView.IntelliSense
7 | {
8 | public class WinAPI
9 | {
10 | /// Отправляет оконное сообщение указанному окну со специфическими параметрами
11 | [DllImport("user32.dll", CharSet = CharSet.Auto)]
12 | static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
13 | [DllImport("User32.dll")]
14 | public static extern int SendMessage(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam);
15 | //=========================================================================================
16 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
17 | public static extern uint RegisterApplicationRestart(string pszCommandline, int dwFlags);
18 | //=========================================================================================
19 | private const int SW_SHOWNOACTIVATE = 4;
20 | private const int HWND_TOPMOST = -1;
21 | private const uint SWP_NOACTIVATE = 0x0010;
22 |
23 | [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
24 | static extern bool SetWindowPos(
25 | IntPtr hWnd, // window handle
26 | IntPtr hWndInsertAfter, // placement-order handle
27 | int X, // horizontal position
28 | int Y, // vertical position
29 | int cx, // width
30 | int cy, // height
31 | uint uFlags); // window positioning flags
32 |
33 | [DllImport("user32.dll")]
34 | static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
35 | //=========================================================================================
36 | public static void ShowInactiveTopmost(Form frm, int x, int y)
37 | {
38 | SetWindowPos(frm.Handle, (IntPtr)HWND_TOPMOST,
39 | x, y, frm.Width, frm.Height,
40 | SWP_NOACTIVATE);
41 |
42 | ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
43 | }
44 |
45 | public static void ShowInactiveTopmost(Form frm, Point pt)
46 | {
47 | ShowInactiveTopmost(frm, pt.X, pt.Y);
48 | }
49 | //==========================================================================================
50 | /// Подгрузка WinAPI функций отвечающих за получение и установку стиля
51 | /// окна для 32/64 версий
52 | [DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)]
53 | public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
54 |
55 | [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)]
56 | public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
57 |
58 | [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
59 | public static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, int dwNewLong);
60 |
61 | [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
62 | public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, int dwNewLong);
63 | //==========================================================================================
64 | /// Возвращает различную информацию об указанном окне учитывая разрядность ОС
65 | public static int GetWindowLong(IntPtr hWnd, int nIndex)
66 | {
67 | if (IntPtr.Size == 4)
68 | return (int)GetWindowLong32(hWnd, nIndex);
69 | else
70 | return (int)(long)GetWindowLongPtr64(hWnd, nIndex);
71 | }
72 | //==========================================================================================
73 | /// Устанавливает различную информацию указанному окну учитывая разрядность ОС
74 | public static int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong)
75 | {
76 | if (IntPtr.Size == 4)
77 | return (int)SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
78 | else
79 | return (int)(long)SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
80 | }
81 | //==========================================================================================
82 | /// Возвращает WORD как нижнюю, правую часть DWORD
83 | private static int GetX_LParam(IntPtr iNumber)
84 | {
85 | return iNumber.ToInt32() & 0x0000FFFF;
86 | }
87 | //==========================================================================================
88 | /// Возвращает WORD как верхнюю, левую часть DWORD
89 | private static int GetY_LParam(IntPtr iNumber)
90 | {
91 | return iNumber.ToInt32() >> 16;
92 | }
93 | //==========================================================================================
94 | /// Возвращает Point как координаты мыши полученные из lParam
95 | public static Point GetPointFromLParam(IntPtr lParam)
96 | {
97 | return new Point(GetX_LParam(lParam), GetY_LParam(lParam));
98 | }
99 | //==========================================================================================
100 | /// Возвращает величину вращения колеса мыши
101 | public static int GetWheelDelta_WParam(IntPtr wParam) {
102 | return (wParam.ToInt32() >> 16) / 120;
103 | }
104 | //==========================================================================================
105 | /// Возвращает текущее активное окно
106 | [DllImport("user32.dll")]
107 | public static extern IntPtr GetForegroundWindow();
108 | }
109 | }
--------------------------------------------------------------------------------
/SA.CodeView/IntelliSense/CompletionVariant.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Collections;
3 | using System;
4 |
5 | namespace SA.CodeView.IntelliSense
6 | {
7 | //#############################################################################################
8 | public enum DataBaseLevel
9 | {
10 | Schema = 1,
11 | Table = 2,
12 | Columns = 3
13 | }
14 | //#############################################################################################
15 | /// Элемент списка вариантов для автоподстановки.
16 | public class CompletionVariant : IComparable
17 | {
18 | public int ImageIndex;
19 | public string Tooltip;
20 | public string Text;
21 | //=========================================================================================
22 | public override string ToString()
23 | {
24 | string sText = string.Format("{0} ({1})", this.Text, this.ImageIndex);
25 | if (!string.IsNullOrEmpty(this.Tooltip))
26 | sText += string.Format(" ({0})", this.Tooltip);
27 | return sText;
28 | }
29 | //=========================================================================================
30 | public int CompareTo(CompletionVariant other)
31 | {
32 | int iResult = this.ImageIndex.CompareTo(other.ImageIndex);
33 | if (iResult != 0)
34 | return iResult;
35 | return this.Text.CompareTo(other.Text);
36 | }
37 | //=========================================================================================
38 | public override int GetHashCode()
39 | {
40 | return this.Text.GetHashCode() + this.ImageIndex;
41 | }
42 | //=========================================================================================
43 | public override bool Equals(object obj)
44 | {
45 | if (obj == null)
46 | return false;
47 | return this.GetHashCode().Equals(obj.GetHashCode());
48 | }
49 | //=========================================================================================
50 | }
51 | //#############################################################################################
52 | public class CompletionVariantList : IEnumerable
53 | {
54 | readonly List Items;
55 | //=========================================================================================
56 | public static CompletionVariantList Combine(CompletionVariantList list, List names, DataBaseLevel type)
57 | {
58 | if (names == null || names.Count == 0)
59 | return list;
60 | if (list == null)
61 | list = new CompletionVariantList();
62 | list.AddRange(names, type);
63 | return list;
64 | }
65 | //=========================================================================================
66 | public static CompletionVariantList Combine(CompletionVariantList list, string name, DataBaseLevel type)
67 | {
68 | if (string.IsNullOrEmpty(name))
69 | return list;
70 | if (list == null)
71 | list = new CompletionVariantList();
72 | list.Add(name, type);
73 | return list;
74 | }
75 | //=========================================================================================
76 | public int Count { get { return this.Items.Count; } }
77 | //=========================================================================================
78 | public CompletionVariant this[int index]
79 | {
80 | get { return this.Items[index]; }
81 | }
82 | //=========================================================================================
83 | CompletionVariantList()
84 | {
85 | this.Items = new List();
86 | }
87 | //=========================================================================================
88 | public IEnumerator GetEnumerator()
89 | {
90 | return this.Items.GetEnumerator();
91 | }
92 | //=========================================================================================
93 | IEnumerator IEnumerable.GetEnumerator()
94 | {
95 | return this.Items.GetEnumerator();
96 | }
97 | //=========================================================================================
98 | public void Add(string name, DataBaseLevel type)
99 | {
100 | CompletionVariant item = new CompletionVariant() { Text = name, ImageIndex = (int)type };
101 | this.Add(item);
102 | }
103 | //=========================================================================================
104 | private void Add(CompletionVariant item)
105 | {
106 | foreach (var oItem in this.Items)
107 | if (item.CompareTo(oItem) == 0)
108 | return;
109 | this.Items.Add(item);
110 | }
111 | //=========================================================================================
112 | public void AddRange(List names, DataBaseLevel type)
113 | {
114 | if (names == null)
115 | return;
116 | foreach (string sName in names)
117 | this.Add(sName, type);
118 | }
119 | //=========================================================================================
120 | public void AddRange(CompletionVariantList variants)
121 | {
122 | foreach (var oItem in variants)
123 | this.Add(oItem.Text, (DataBaseLevel)oItem.ImageIndex);
124 | }
125 | //=========================================================================================
126 | public override string ToString()
127 | {
128 | return string.Format("Count = {0}", this.Items.Count);
129 | }
130 | //=========================================================================================
131 | }
132 | //#############################################################################################
133 | }
134 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/TextSpan.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Drawing;
5 |
6 | namespace SA.CodeView
7 | {
8 | /// Allow to add decoration to some part of text line.
9 | public class TextSpan : IComparable
10 | {
11 | public readonly TextPoint Start;
12 | public readonly TextPoint End;
13 | public readonly Brush Brush;
14 | public readonly Pen Pen;
15 | //=========================================================================================
16 | public TextSpan(Brush background, Pen border, TextPoint start, TextPoint end)
17 | {
18 | this.Start = start;
19 | this.End = end;
20 | this.Brush = background;
21 | this.Pen = border;
22 | }
23 | //=========================================================================================
24 | public int CompareTo(TextSpan other)
25 | {
26 | return this.Start.CompareTo(other.Start);
27 | }
28 | //=========================================================================================
29 | }
30 | //#############################################################################################
31 | public class TextSpanCollection : IEnumerable
32 | {
33 | readonly List List;
34 | readonly CodeViewer Viewer;
35 | //=========================================================================================
36 | internal TextSpanCollection(CodeViewer viewer)
37 | {
38 | this.List = new List();
39 | this.Viewer = viewer;
40 | }
41 | //=========================================================================================
42 | public void Add(TextSpan span)
43 | {
44 | this.List.Add(span);
45 | this.List.Sort();
46 | this.Viewer.Body.Invalidate(false);
47 | }
48 | //=========================================================================================
49 | public void Add(Brush brush, int lineStart, int chrStart, int lineEnd, int chrEnd)
50 | {
51 | this.Add(brush, null, lineStart, chrStart, lineEnd, chrEnd);
52 | }
53 | //=========================================================================================
54 | public void Add(Brush brush, Pen pen, int lineStart, int chrStart, int lineEnd, int chrEnd)
55 | {
56 | if (lineStart >= this.Viewer.Document.Count || lineEnd >= this.Viewer.Document.Count)
57 | return;
58 | int iColStart = this.Viewer.Caret.GetColumn(this.Viewer.Document[lineStart].Text, chrStart);
59 | int iColEnd = this.Viewer.Caret.GetColumn(this.Viewer.Document[lineEnd].Text, chrEnd);
60 | TextPoint pStart = new TextPoint(lineStart, iColStart, chrStart);
61 | TextPoint pEnd = new TextPoint(lineEnd, iColEnd, chrEnd);
62 | if (lineEnd == lineStart)
63 | {
64 | TextSpan oSpan = new TextSpan(brush, pen, pStart, pEnd);
65 | this.Add(oSpan);
66 | }
67 | else
68 | {
69 | TextPoint p1, p2;
70 | string sLine = this.Viewer.Document[lineStart].Text;
71 | p2 = new TextPoint(lineStart, TextCaret.GetLastCol(sLine, this.Viewer._TabSize), sLine.Length);
72 | TextSpan oSpan = new TextSpan(brush, pen, pStart, p2);
73 | this.Add(oSpan);
74 | for (int iLine = lineStart + 1; iLine < lineEnd; iLine++)
75 | {
76 | sLine = this.Viewer.Document[iLine].Text;
77 | p1 = new TextPoint(iLine, 0, 0);
78 | p2 = new TextPoint(iLine, TextCaret.GetLastCol(sLine, this.Viewer._TabSize), sLine.Length);
79 | oSpan = new TextSpan(brush, pen, p1, p2);
80 | this.Add(oSpan);
81 | }
82 | p1 = new TextPoint(lineEnd, 0, 0);
83 | oSpan = new TextSpan(brush, pen, p1, pEnd);
84 | this.Add(oSpan);
85 | }
86 | }
87 | //=========================================================================================
88 | public void Add(Brush brush, int lineStart, int chrStart, int length)
89 | {
90 | int iLine = lineStart, iChar = chrStart;
91 | while (length > 0 && iLine < this.Viewer.Document.Count)
92 | {
93 | string sLine = this.Viewer.Document[iLine].Text;
94 | if (iChar + length < sLine.Length)
95 | {
96 | iChar += length;
97 | length = 0;
98 | }
99 | else
100 | {
101 | length -= sLine.Length - iChar;
102 | iChar = 0;
103 | iLine++;
104 | }
105 | }
106 | if (length > 0)
107 | {
108 | iLine = this.Viewer.Document.Count - 1;
109 | iChar = this.Viewer.Document[iLine].Text.Length;
110 | }
111 |
112 | this.Add(brush, null, lineStart, chrStart, iLine, iChar);
113 | }
114 | //=========================================================================================
115 | public void AddRange(IEnumerable spans)
116 | {
117 | this.List.AddRange(spans);
118 | this.List.Sort();
119 | this.Viewer.Body.Invalidate(false);
120 | }
121 | //=========================================================================================
122 | public void Clear()
123 | {
124 | this.List.Clear();
125 | this.Viewer.Body.Invalidate(false);
126 | }
127 | //=========================================================================================
128 | public TextSpan this[int index]
129 | {
130 | get { return this.List[index]; }
131 | }
132 | //=========================================================================================
133 | public int Count { get { return this.List.Count; } }
134 | //=========================================================================================
135 | public IEnumerator GetEnumerator()
136 | {
137 | return this.List.GetEnumerator();
138 | }
139 | //=========================================================================================
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/FindForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/TestForms/StartForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/SA.CodeView/Languages/VisualBasicSyntaxSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using SA.CodeView.ParsingOnElements;
5 | using System.Drawing;
6 | using SA.CodeView.Parsing;
7 |
8 | namespace SA.CodeView.Languages
9 | {
10 | class VisualBasicSyntaxSettings : SyntaxSettings
11 | {
12 | //=========================================================================================
13 | public VisualBasicSyntaxSettings()
14 | {
15 | this.Operators = new char[] { '=', '+', '-', '/', '*', '%', '>', '<', '&', '|', '^', '~', '(', ')', '[', ']', ',' };
16 | }
17 | //=========================================================================================
18 | protected override List CreateElements()
19 | {
20 | var elements = new List();
21 | return elements;
22 | }
23 | //=========================================================================================
24 | protected override Dictionary CreateTextStyles()
25 | {
26 | var styles = base.CreateTextStyles();
27 | this.AddStyle(styles, new TextStyle(S_OPERATORS, Color.Black));
28 | this.AddStyle(styles, new TextStyle(S_STRINGS, Color.Maroon));
29 | this.AddStyle(styles, new TextStyle(S_MULTI_COMMENT, Color.Green));
30 | this.AddStyle(styles, new TextStyle(S_SINGLE_COMMENT, Color.Green));
31 | this.AddStyle(styles, new TextStyle(S_IDENTIFIER, Color.Black));
32 | this.AddStyle(styles, new TextStyle(S_NUMBERS, Color.Black));
33 | this.AddStyle(styles, new TextStyle(S_KEYWORDS_1, Color.Blue, true));
34 | return styles;
35 | }
36 | //=========================================================================================
37 | internal override ScannerSpecification CreateScannerSpecification()
38 | {
39 | var oSpec = new ScannerSpecification();
40 | oSpec.AddLiteral("l", CharType.Letters, '_');
41 | oSpec.AddLiteral("d", CharType.Numbers);
42 | oSpec.AddLiteral("minus", '-');
43 | oSpec.AddLiteral("asterisk", '*');
44 | oSpec.AddLiteral("slash", '/');
45 | oSpec.AddLiteral("backSlash", '\\');
46 | oSpec.AddLiteral("operators", '=', '>', '<', ';', ',', '.', '+', ')', '(', '|', '&');
47 | oSpec.AddLiteral("singleQuote", '\'');
48 | oSpec.AddLiteral("doubleQuote", '"');
49 | oSpec.AddLiteral("caretReturn", '\n');
50 |
51 | oSpec.AddTokenDeclaration("id", "l{l|d}");
52 | oSpec.AddTokenDeclaration("number", "d{d}");
53 | oSpec.AddTokenDeclaration("operator", "(operators|minus)");
54 | oSpec.AddBoundedToken("charConst", "singleQuote", "singleQuote", "backSlash");
55 | oSpec.AddBoundedToken("comment1", "slash asterisk", "asterisk slash", null);
56 | oSpec.AddBoundedToken("comment2", "slash slash", "caretReturn", null);
57 | oSpec.AddBoundedToken("stringConst", "doubleQuote", "doubleQuote", "backSlash");
58 |
59 | return oSpec;
60 | }
61 | //=========================================================================================
62 | protected override void FillKeywordGroups(Dictionary dictionary)
63 | {
64 | base.FillKeywordGroups(dictionary);
65 | TextStyle oStyle;
66 |
67 | ///Ключевые слова первого эшелона
68 | oStyle = this.GetStyleByName(S_KEYWORDS_1);
69 | this.LoadKeywordsToGroup(dictionary, oStyle, @"
70 | AddHandler
71 | AddressOf
72 | Alias
73 | And
74 |
75 | AndAlso
76 | As
77 | Boolean
78 | ByRef
79 |
80 | Byte
81 | ByVal
82 | Call
83 | Case
84 |
85 | Catch
86 | CBool
87 | CByte
88 | CChar
89 |
90 | CDate
91 | CDec
92 | CDbl
93 | Char
94 |
95 | CInt
96 | Class
97 | CLng
98 | CObj
99 |
100 | Const
101 | Continue
102 | CSByte
103 | CShort
104 |
105 | CSng
106 | CStr
107 | CType
108 | CUInt
109 |
110 | CULng
111 | CUShort
112 | Date
113 | Decimal
114 |
115 | Declare
116 | Default
117 | Delegate
118 | Dim
119 |
120 | DirectCast
121 | Do
122 | Double
123 | Each
124 |
125 | Else
126 | ElseIf
127 | End
128 | EndIf
129 |
130 | Enum
131 | Erase
132 | Error
133 | Event
134 |
135 | Exit
136 | False
137 | Finally
138 | For
139 |
140 | Friend
141 | Function
142 | Get
143 | GetType
144 |
145 | GetXMLNamespace
146 | Global
147 | GoSub
148 | GoTo
149 |
150 | Handles
151 | If
152 | Implements
153 |
154 | Imports
155 | In
156 | Inherits
157 |
158 | Integer
159 | Interface
160 | Is
161 | IsNot
162 |
163 | Let
164 | Lib
165 | Like
166 | Long
167 |
168 | Loop
169 | Me
170 | Mod
171 | Module
172 |
173 | MustInherit
174 | MustOverride
175 | MyBase
176 | MyClass
177 |
178 | Namespace
179 | Narrowing
180 | New
181 | Next
182 |
183 | Not
184 | Nothing
185 | NotInheritable
186 | NotOverridable
187 |
188 | Object
189 | Of
190 | On
191 | Operator
192 |
193 | Option
194 | Optional
195 | Or
196 | OrElse
197 |
198 | Overloads
199 | Overridable
200 | Overrides
201 | ParamArray
202 |
203 | Partial
204 | Private
205 | Property
206 | Protected
207 |
208 | Public
209 | RaiseEvent
210 | ReadOnly
211 | ReDim
212 |
213 | REM
214 | RemoveHandler
215 | Resume
216 | Return
217 |
218 | SByte
219 | Select
220 | Set
221 | Shadows
222 |
223 | Shared
224 | Short
225 | Single
226 | Static
227 |
228 | Step
229 | Stop
230 | String
231 | Structure
232 |
233 | Sub
234 | SyncLock
235 | Then
236 | Throw
237 |
238 | To
239 | True
240 | Try
241 | TryCast
242 |
243 | TypeOf
244 | Variant
245 | Wend
246 | UInteger
247 |
248 | ULong
249 | UShort
250 | Using
251 | When
252 |
253 | While
254 | Widening
255 | With
256 | WithEvents
257 |
258 | WriteOnly
259 | Xor
260 | #Const
261 | #Else
262 |
263 | #ElseIf
264 | #End
265 | #If
266 | ");
267 | }
268 | //=========================================================================================
269 | internal override TextStyle GetStyleFor(Token token, string styleName)
270 | {
271 | if (token.TokenTypeName == "charConst")
272 | return this.TextStyles[S_STRINGS];
273 |
274 | return base.GetStyleFor(token, styleName);
275 | }
276 | //=========================================================================================
277 | }
278 | }
279 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/CodeViewerBody.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 17, 17
122 |
123 |
--------------------------------------------------------------------------------
/SA.CodeView/Languages/MySqlSyntaxSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 | using SA.CodeView.ParsingOnElements;
4 | using SA.CodeView.Parsing;
5 |
6 | namespace SA.CodeView.Languages
7 | {
8 | class MySqlSyntaxSettings : SyntaxSettings
9 | {
10 | //=========================================================================================
11 | public MySqlSyntaxSettings()
12 | {
13 | this.Operators = new char[] { '=', '+', '-', '/', '*', '%', '>', '<', '&', '|', '^', '~', '(', ')', '[', ']', ',' };
14 | }
15 | //=========================================================================================
16 | protected override List CreateElements()
17 | {
18 | var elements = new List();
19 | return elements;
20 | }
21 | //=========================================================================================
22 | protected override Dictionary CreateTextStyles()
23 | {
24 | var styles = base.CreateTextStyles();
25 | this.AddStyle(styles, new TextStyle(S_OPERATORS, Color.Red));
26 | this.AddStyle(styles, new TextStyle(S_STRINGS, Color.Red));
27 | this.AddStyle(styles, new TextStyle(S_MULTI_COMMENT, Color.Green));
28 | this.AddStyle(styles, new TextStyle(S_SINGLE_COMMENT, Color.Green));
29 | this.AddStyle(styles, new TextStyle(S_IDENTIFIER, Color.Black));
30 | this.AddStyle(styles, new TextStyle(S_NUMBERS, Color.Teal));
31 | this.AddStyle(styles, new TextStyle(S_KEYWORDS_1, Color.Blue));
32 | this.AddStyle(styles, new TextStyle(S_SYS_FUNCTION, Color.DarkBlue));
33 |
34 | return styles;
35 | }
36 | //=========================================================================================
37 | internal override ScannerSpecification CreateScannerSpecification()
38 | {
39 | var oSpec = new ScannerSpecification();
40 | oSpec.AddLiteral("l", CharType.Letters, '_', '@');
41 | oSpec.AddLiteral("d", CharType.Numbers);
42 | oSpec.AddLiteral("minus", '-');
43 | oSpec.AddLiteral("asterisk", '*');
44 | oSpec.AddLiteral("slash", '/');
45 | oSpec.AddLiteral("poundkey", '#');
46 | oSpec.AddLiteral("operators", '=', '>', '<', ';', ',', '.', '+', ')', '(', '|', '&');
47 | oSpec.AddLiteral("n", 'N', 'n');
48 | oSpec.AddLiteral("singleQuote", '\'');
49 | oSpec.AddLiteral("doubleQuote", '"');
50 | oSpec.AddLiteral("caretReturn", '\n');
51 | oSpec.AddLiteral("tilda", '`');
52 |
53 | oSpec.AddTokenDeclaration("id", "(n|l){l|d}");
54 | oSpec.AddTokenDeclaration("number", "d{d}");
55 | oSpec.AddTokenDeclaration("operator", "(operators|minus)"); // |asterisk
56 | oSpec.AddBoundedToken("stringConst", "singleQuote", "singleQuote", "singleQuote");
57 | oSpec.AddBoundedToken("stringConst", "n singleQuote", "singleQuote", "singleQuote");
58 | oSpec.AddBoundedToken("stringConst", "doubleQuote", "doubleQuote", "doubleQuote");
59 | oSpec.AddBoundedToken("comment1", "slash asterisk", "asterisk slash", null);
60 | oSpec.AddBoundedToken("comment2", "minus minus", "caretReturn", null);
61 | oSpec.AddBoundedToken("comment3", "poundkey", "caretReturn", null);
62 | oSpec.AddBoundedToken("quotedId", "tilda", "tilda", "tilda");
63 |
64 | return oSpec;
65 | }
66 | //=========================================================================================
67 | protected override void FillKeywordGroups(Dictionary dictionary)
68 | {
69 | base.FillKeywordGroups(dictionary);
70 |
71 | //Ключевые слова первого эшелона
72 | TextStyle oStyle = this.GetStyleByName(S_KEYWORDS_1);
73 | this.LoadKeywordsToGroup(dictionary, oStyle, @"
74 | add
75 | after
76 | algorithm
77 | all
78 | alter
79 | and
80 | as
81 | asc
82 | auto_increment
83 | before
84 | begin
85 | between
86 | binary
87 | both
88 | by
89 | change
90 | character
91 | charset
92 | check
93 | client
94 | collate
95 | column
96 | columns
97 | comment
98 | commit
99 | constraint
100 | contains
101 | create
102 | cross
103 | data
104 | database
105 | databases
106 | declare
107 | default
108 | definer
109 | delayed
110 | delete
111 | delimiter
112 | desc
113 | describe
114 | deterministic
115 | distinct
116 | do
117 | drop
118 | each
119 | enclosed
120 | end
121 | engine
122 | escaped
123 | event
124 | execute
125 | exists
126 | explain
127 | field
128 | fields
129 | file
130 | flush
131 | for
132 | foreign
133 | from
134 | function
135 | grant
136 | group
137 | having
138 | identified
139 | if
140 | ignore
141 | index
142 | infile
143 | innodb
144 | insert
145 | into
146 | join
147 | key
148 | keys
149 | kill
150 | leading
151 | left
152 | like
153 | limit
154 | lines
155 | load
156 | local
157 | lock
158 | low_priority
159 | modify
160 | myisam
161 | natural
162 | new
163 | not
164 | null
165 | on
166 | optimize
167 | option
168 | optionally
169 | or
170 | order
171 | out
172 | outer
173 | outfile
174 | primary
175 | procedure
176 | process
177 | read
178 | references
179 | regexp
180 | reload
181 | rename
182 | repeat
183 | replace
184 | replication
185 | returns
186 | revoke
187 | rlike
188 | routine
189 | row
190 | security
191 | select
192 | set
193 | show
194 | shutdown
195 | slave
196 | soname
197 | sql
198 | status
199 | straight_join
200 | super
201 | table
202 | tables
203 | tablespace
204 | teminated
205 | temporary
206 | to
207 | trailing
208 | trigger
209 | unique
210 | unlock
211 | unsigned
212 | update
213 | use
214 | user
215 | using
216 | values
217 | variables
218 | view
219 | where
220 | while
221 | with
222 | write
223 | xor
224 | zerofill
225 | bigint bit blob char date datetime decimal double doubleprecision enum float float4 float8 int int1 int2 int3 int4 int8 integer long longblob longtext mediumblob mediumint mediumtext middleint numeric real smallint text time timestamp tinyint tinytext tinyblob varbinary varchar varying
226 | ");
227 |
228 | //ключевые слова - системные функции
229 | oStyle = this.GetStyleByName(S_SYS_FUNCTION);
230 | this.LoadKeywordsToGroup(dictionary, oStyle,
231 | "abs acos adddate ascii asin atan atan2 avg bin bit_and bit_count bit_or ceiling char_lengh character_length concat conv cos cot count curdate curtime current_time current_timestamp date_add date_format date_sub dayname dayofmonth dayofweek dayofyear degrees elt encrypt exp find_in_set floor format from_days from_unixtime get_lock greatest hex hour ifnull instr isnull interval last_insert_id lcase lower least length locate log log10 lpad ltrim max mid min minute mod month monthname now oct octet_length password period_add period_diff pi position pow quarter radians rand release_lock reverse right round rpad rtrim second sec_to_time session_user sign sin soundex space sqrt strcmp substring substring_index sysdate system_user std sum tan time_format time_to_sec to_days trim truncate ucase unix_timestamp version week weekday year");
232 | }
233 | //=========================================================================================
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/SA.CodeView/Coco/Parser.frame:
--------------------------------------------------------------------------------
1 | /*----------------------------------------------------------------------
2 | Compiler Generator Coco/R,
3 | Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
4 | extended by M. Loeberbauer & A. Woess, Univ. of Linz
5 | with improvements by Pat Terry, Rhodes University
6 |
7 | This program is free software; you can redistribute it and/or modify it
8 | under the terms of the GNU General Public License as published by the
9 | Free Software Foundation; either version 2, or (at your option) any
10 | later version.
11 |
12 | This program is distributed in the hope that it will be useful, but
13 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 | for more details.
16 |
17 | You should have received a copy of the GNU General Public License along
18 | with this program; if not, write to the Free Software Foundation, Inc.,
19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 |
21 | As an exception, it is allowed to write an extension of Coco/R that is
22 | used as a plugin in non-free software.
23 |
24 | If not otherwise stated, any source code generated by Coco/R (other than
25 | Coco/R itself) does not fall under the GNU General Public License.
26 | ----------------------------------------------------------------------*/
27 | -->begin
28 | using System;
29 | using System.Collections;
30 | using System.Collections.Generic;
31 |
32 | -->namespace
33 |
34 | partial class Parser
35 | {
36 | -->constants
37 | const bool T = true;
38 | const bool x = false;
39 | const int minErrDist = 2;
40 |
41 | public Scanner scanner;
42 | public ErrorCollection Errors;
43 |
44 | public Token t; // last recognized token
45 | public Token la; // lookahead token
46 | int errDist = minErrDist;
47 |
48 | -->declarations
49 |
50 | public Parser(Scanner scanner)
51 | {
52 | this.scanner = scanner;
53 | this.Errors = new ErrorCollection(scanner.FileName);
54 | }
55 |
56 | void SynErr(int n)
57 | {
58 | if (errDist >= minErrDist)
59 | this.Errors.SynErr(la.line, la.col, n);
60 | errDist = 0;
61 | }
62 |
63 | public void SemErr(string msg)
64 | {
65 | if (errDist >= minErrDist)
66 | this.Errors.SemErr(t.line, t.col, msg);
67 | errDist = 0;
68 | }
69 |
70 | void Get()
71 | {
72 | for (; ; )
73 | {
74 | t = la;
75 | la = scanner.Scan();
76 | if (la.kind <= maxT) { ++errDist; break; }
77 | -->pragmas
78 | la = t;
79 | }
80 | }
81 |
82 | void Expect(int n)
83 | {
84 | if (la.kind == n) Get(); else { SynErr(n); }
85 | }
86 |
87 | bool StartOf(int s)
88 | {
89 | return set[s, la.kind];
90 | }
91 |
92 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
93 | void ExpectWeak(int n, int follow)
94 | {
95 | if (la.kind == n) Get();
96 | else
97 | {
98 | SynErr(n);
99 | while (!StartOf(follow)) Get();
100 | }
101 | }
102 |
103 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
104 | bool WeakSeparator(int n, int syFol, int repFol)
105 | {
106 | int kind = la.kind;
107 | if (kind == n) { Get(); return true; }
108 | else if (StartOf(repFol)) { return false; }
109 | else
110 | {
111 | SynErr(n);
112 | while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind]))
113 | {
114 | Get();
115 | kind = la.kind;
116 | }
117 | return StartOf(syFol);
118 | }
119 | }
120 |
121 |
122 | -->productions
123 |
124 | void _Parse()
125 | {
126 | la = new Token();
127 | la.val = "";
128 | Get();
129 | -->parseRoot
130 |
131 | scanner.RollBack();
132 | }
133 |
134 | bool[,] set = {
135 | -->initialization
136 | };
137 | } // end Parser
138 |
139 |
140 | public class ErrorDescription
141 | {
142 | public enum ErrorType
143 | {
144 | Syntax,
145 | Semantic,
146 | Warning,
147 | }
148 | public string File;
149 | public string Msg;
150 | public ErrorType Type;
151 | public string StringType
152 | {
153 | get
154 | {
155 | switch(Type)
156 | {
157 | case ErrorType.Syntax:
158 | return "Syntax";
159 | case ErrorType.Semantic:
160 | return "Semantic";
161 | case ErrorType.Warning:
162 | return "Warning";
163 | default:
164 | return "Indefinite error type.";
165 | }
166 | }
167 | }
168 | public int Row;
169 | public int Col;
170 | //=======================================================================================================
171 | public ErrorDescription()
172 | {
173 | }
174 | //=======================================================================================================
175 | public ErrorDescription(string file, string msg, ErrorType type, int row, int col)
176 | {
177 | File = file;
178 | Msg = msg;
179 | Type = type;
180 | Row = row;
181 | Col = col;
182 | }
183 | }
184 |
185 |
186 | public class ErrorCollection : IEnumerable
187 | {
188 | public static string errMsgFormat = "Line {0}, col {1}: {2}"; // 0=line, 1=column, 2=text
189 | List Errors = new List();
190 | public int NoWarningCount = 0; //number of errors, not include warnings
191 | public int WarningCount = 0; //number of warnings
192 | string _file;
193 |
194 | public int Count
195 | {
196 | get
197 | {
198 | if (this.Errors == null)
199 | return 0;
200 | else
201 | return this.Errors.Count;
202 | }
203 | }
204 | public IEnumerator GetEnumerator()
205 | {
206 | return this.Errors.GetEnumerator();
207 | }
208 | public ErrorDescription this[int index]
209 | {
210 | get { return this.Errors[index]; }
211 | }
212 |
213 | public ErrorCollection(string file)
214 | {
215 | _file = file;
216 | }
217 |
218 | public void SynErr(int line, int col, int n)
219 | {
220 | string s;
221 | switch (n)
222 | {
223 | -->errors
224 | default: s = "error " + n; break;
225 | }
226 |
227 | this.Errors.Add(new ErrorDescription(
228 | _file,
229 | string.Format(errMsgFormat, line, col, s),
230 | ErrorDescription.ErrorType.Syntax,
231 | line,
232 | col));
233 |
234 | NoWarningCount++;
235 | }
236 |
237 | public void SemErr(int line, int col, string s)
238 | {
239 | this.Errors.Add(new ErrorDescription(
240 | _file,
241 | string.Format(errMsgFormat, line, col, s),
242 | ErrorDescription.ErrorType.Semantic,
243 | line,
244 | col));
245 | NoWarningCount++;
246 | }
247 | }
248 |
249 | public class AnalyzingException : Exception
250 | {
251 | public AnalyzingException(string m) : base(m) { }
252 | }
253 | $$$
254 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/IntelliSense/CodeCompletorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 | using SA.CodeView;
4 | using SA.CodeView.IntelliSense;
5 | using Tests.IntelliSense.BLL;
6 |
7 | namespace Tests.IntelliSense
8 | {
9 | [TestFixture]
10 | public class CodeCompletorTests
11 | {
12 | CodeViewer Viewer;
13 | //=========================================================================================
14 | [SetUp]
15 | public void SetUp()
16 | {
17 | this.Viewer = new CodeViewer();
18 | this.Viewer.Language = PredefinedLanguage.MsSql;
19 |
20 | var oTestProvider = new TestDbInfoProvider();
21 | var oSuggestionBuilder = new EditQueryRegExBuilder(Viewer, oTestProvider);
22 | oSuggestionBuilder.DefaultSchema = "Schema_Second";
23 |
24 | Viewer.UseSuggestionRules(oSuggestionBuilder);
25 | }
26 | //=========================================================================================
27 | [Test]
28 | public void Get_variants_for_schemas()
29 | {
30 | Viewer.Text = "select * from ";
31 | Viewer.Caret.MoveDocEnd(true);
32 |
33 | var variants = Viewer.CodeCompletor.Builder.GetVariants();
34 | Assert.IsNotNull(variants);
35 |
36 | var expectedVariants = new List(new[]
37 | {
38 | new CompletionVariant() { Text = "Schema_First", ImageIndex = (int)DataBaseLevel.Schema },
39 | new CompletionVariant() { Text = "Schema_Second", ImageIndex = (int)DataBaseLevel.Schema },
40 | new CompletionVariant() { Text = "Schema Third", ImageIndex = (int)DataBaseLevel.Schema },
41 | new CompletionVariant() { Text = "Fruits", ImageIndex = (int)DataBaseLevel.Table },
42 | new CompletionVariant() { Text = "Vitamins", ImageIndex = (int)DataBaseLevel.Table },
43 | });
44 | Assert.That(variants, Is.EquivalentTo(expectedVariants));
45 | }
46 | //=========================================================================================
47 | [Test]
48 | public void Get_variants_for_tables_after_schema()
49 | {
50 | this.Viewer.Text = "select * from Schema_First.";
51 | this.Viewer.Caret.MoveDocEnd(true);
52 |
53 | var variants = Viewer.CodeCompletor.Builder.GetVariants();
54 | var expectedVariants = new List(new[]
55 | {
56 | new CompletionVariant() { Text = "User", ImageIndex = (int)DataBaseLevel.Table },
57 | new CompletionVariant() { Text = "Org", ImageIndex = (int)DataBaseLevel.Table },
58 | });
59 |
60 | Assert.That(variants, Is.EquivalentTo(expectedVariants));
61 | }
62 | //=========================================================================================
63 | [Test]
64 | public void Get_variants_for_columns()
65 | {
66 | this.Viewer.Text = "select from Schema_First.User";
67 | this.Viewer.Caret.MoveToPos(0, "select ".Length, true);
68 |
69 | var variants = this.Viewer.CodeCompletor.Builder.GetVariants();
70 | var expectedVariants = new List(new[]
71 | {
72 | new CompletionVariant() { Text = "First Name", ImageIndex = (int)DataBaseLevel.Columns },
73 | new CompletionVariant() { Text = "Last Name", ImageIndex = (int)DataBaseLevel.Columns },
74 | new CompletionVariant() { Text = "User", ImageIndex = (int)DataBaseLevel.Table },
75 | new CompletionVariant() { Text = "Fruits", ImageIndex = (int)DataBaseLevel.Table },
76 | new CompletionVariant() { Text = "Vitamins", ImageIndex = (int)DataBaseLevel.Table },
77 | new CompletionVariant() { Text = "Schema_First", ImageIndex = (int)DataBaseLevel.Schema },
78 | new CompletionVariant() { Text = "Schema_Second", ImageIndex = (int)DataBaseLevel.Schema },
79 | new CompletionVariant() { Text = "Schema Third", ImageIndex = (int)DataBaseLevel.Schema },
80 | });
81 | Assert.That(variants, Is.EquivalentTo(expectedVariants));
82 | }
83 | //=========================================================================================
84 | /// Getting column variants when we know table name.
85 | [Test]
86 | public void Get_variants_for_items_2_columns_for_table()
87 | {
88 | this.Viewer.Text = "select Fruits.";
89 | this.Viewer.Caret.MoveDocEnd(true);
90 |
91 | var variants = this.Viewer.CodeCompletor.Builder.GetVariants();
92 | var expectedVariants = new List(new[]
93 | {
94 | new CompletionVariant() { Text = "Apple", ImageIndex = (int)DataBaseLevel.Columns },
95 | new CompletionVariant() { Text = "Lemon", ImageIndex = (int)DataBaseLevel.Columns },
96 | });
97 | Assert.That(variants, Is.EquivalentTo(expectedVariants));
98 | }
99 | //=========================================================================================
100 | [Test]
101 | public void Get_variants_for_columns_when_join_is_used()
102 | {
103 | this.Viewer.Text = @"select from Schema_First.User \r\n left outer join Schema_Second.Fruits";
104 | this.Viewer.Caret.MoveToPos(0, "select ".Length, true);
105 |
106 | var variants = this.Viewer.CodeCompletor.Builder.GetVariants();
107 | var expectedVariants = new List(new[]
108 | {
109 | new CompletionVariant() { Text = "First Name", ImageIndex = (int)DataBaseLevel.Columns },
110 | new CompletionVariant() { Text = "Last Name", ImageIndex = (int)DataBaseLevel.Columns },
111 | new CompletionVariant() { Text = "Apple", ImageIndex = (int)DataBaseLevel.Columns },
112 | new CompletionVariant() { Text = "Lemon", ImageIndex = (int)DataBaseLevel.Columns },
113 | new CompletionVariant() { Text = "User", ImageIndex = (int)DataBaseLevel.Table },
114 | new CompletionVariant() { Text = "Fruits", ImageIndex = (int)DataBaseLevel.Table },
115 | new CompletionVariant() { Text = "Vitamins", ImageIndex = (int)DataBaseLevel.Table },
116 | new CompletionVariant() { Text = "Schema_First", ImageIndex = (int)DataBaseLevel.Schema },
117 | new CompletionVariant() { Text = "Schema_Second", ImageIndex = (int)DataBaseLevel.Schema },
118 | new CompletionVariant() { Text = "Schema Third", ImageIndex = (int)DataBaseLevel.Schema },
119 | });
120 | Assert.That(variants, Is.EquivalentTo(expectedVariants));
121 | }
122 | //=========================================================================================
123 | [Test]
124 | public void AutoComplete_table_name_after_schema()
125 | {
126 | Viewer.Text = "Select * from \t Schema_Second.fr";
127 | Viewer.Caret.MoveDocEnd(true);
128 |
129 | Viewer.CodeCompletor.AutoComplete();
130 | Assert.AreEqual("Select * from \t Schema_Second.Fruits", Viewer.Text);
131 | }
132 | //=========================================================================================
133 | [Test]
134 | public void AutoComplete_column_name()
135 | {
136 | Viewer.Text = "Select N from \t Schema_First.Org";
137 | Viewer.Caret.MoveToPos(this.Viewer.Caret.Line, "Select N".Length, true);
138 |
139 | Viewer.CodeCompletor.AutoComplete();
140 | Assert.AreEqual("Select Name from \t Schema_First.Org", Viewer.Text);
141 | }
142 | //=========================================================================================
143 | [Test]
144 | public void AutoComplete_with_one_variant_after_join_and_schema()
145 | {
146 | this.Viewer.Text = "Select lemon from Schema_Second.Fruits\r\ninner join Schema_Second.fr";
147 | this.Viewer.Caret.MoveDocEnd(true);
148 |
149 | this.Viewer.CodeCompletor.AutoComplete();
150 | //Text should be the same as before
151 | Assert.AreEqual("Select lemon from Schema_Second.Fruits\r\ninner join Schema_Second.Fruits", this.Viewer.Text);
152 | }
153 | //=========================================================================================
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/SA.CodeView/Editing/UndoRedoManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SA.CodeView.Editing
5 | {
6 | class UndoRedoManager
7 | {
8 | private int CurrentStartLine;
9 | private int CurrentStartChar;
10 | private int CurrentEndLine;
11 | private int CurrentEndChar;
12 | private string PreviousText;
13 |
14 | private readonly Stack Operations;
15 | private readonly Stack UndoneOperations;
16 |
17 | private readonly CodeViewer Viewer;
18 | private readonly EditingController EditingController;
19 | private readonly TextCaret Caret;
20 | private readonly Document Doc;
21 |
22 | public UndoRedoManager(CodeViewer viewer, EditingController editingController)
23 | {
24 | Viewer = viewer;
25 | EditingController = editingController;
26 | Caret = Viewer.Caret;
27 | Doc = Viewer.Document;
28 | Operations = new Stack();
29 | UndoneOperations = new Stack();
30 |
31 | StartNewUndoRedoOperation();
32 | }
33 |
34 | public void Undo()
35 | {
36 | if (CurrentStartChar < CurrentEndChar)
37 | {
38 | var currentOperation = TakeCurrentTypingOperation();
39 | UndoTyping(currentOperation);
40 | UndoneOperations.Push(currentOperation);
41 | StartNewUndoRedoOperation();
42 | return;
43 | }
44 |
45 | if (Operations.Count == 0)
46 | return;
47 |
48 | var operation = Operations.Pop();
49 | switch (operation.Type)
50 | {
51 | case UndoRedoOperationType.Insert:
52 | UndoTyping(operation);
53 | break;
54 | case UndoRedoOperationType.CaretReturn:
55 | Viewer.Caret.MoveToPos(operation.StartLine, operation.StartChar, true);
56 | EditingController.ProcessDeleteKey(false);
57 | break;
58 | case UndoRedoOperationType.Remove:
59 | Viewer.Caret.MoveToPos(operation.StartLine, operation.StartChar, true);
60 | EditingController.PasteText(operation.Text);
61 | break;
62 | case UndoRedoOperationType.Paste:
63 | Viewer.Caret.MoveToPos(operation.StartLine, operation.StartChar, true);
64 | EditingController.DeleteText(operation.StartLine, operation.StartChar, operation.EndLine, operation.EndChar);
65 | if (!string.IsNullOrEmpty(operation.PreviousText))
66 | EditingController.PasteText(operation.PreviousText);
67 | break;
68 | default:
69 | throw new NotSupportedException();
70 | }
71 | UndoneOperations.Push(operation);
72 | StartNewUndoRedoOperation();
73 | }
74 |
75 | public void Redo()
76 | {
77 | SaveCurrentOperationToStack(false);
78 |
79 | if (UndoneOperations.Count == 0)
80 | return;
81 |
82 | var operation = UndoneOperations.Pop();
83 | switch (operation.Type)
84 | {
85 | case UndoRedoOperationType.Insert:
86 | case UndoRedoOperationType.CaretReturn:
87 | case UndoRedoOperationType.Paste:
88 | Viewer.Caret.MoveToPos(operation.StartLine, operation.StartChar, true);
89 | Viewer.Caret.MoveToPos(operation.EndLine, operation.EndChar, false);
90 | EditingController.PasteText(operation.Text);
91 | StartNewUndoRedoOperation();
92 | Operations.Push(operation);
93 | break;
94 | case UndoRedoOperationType.Remove:
95 | Viewer.Caret.MoveToPos(operation.StartLine, operation.StartChar, true);
96 | EditingController.DeleteText(operation.StartLine, operation.StartChar, operation.EndLine, operation.EndChar);
97 | Operations.Push(operation);
98 | break;
99 | default:
100 | throw new NotSupportedException();
101 | }
102 | }
103 |
104 | public void ProcessChar()
105 | {
106 | string selectionText = Viewer.SelectionText;
107 |
108 | if (selectionText.Length > 0 ||
109 | Caret.Line != CurrentEndLine || Caret.Char != CurrentEndChar)
110 | {
111 | var operation = SaveCurrentOperationToStack();
112 | PreviousText = selectionText;
113 | }
114 | CurrentEndChar++;
115 | }
116 |
117 | public void ProcessEnterKey()
118 | {
119 | SaveCurrentOperationToStack();
120 | var operation = new UndoRedoOperation
121 | {
122 | Type = UndoRedoOperationType.CaretReturn,
123 | StartLine = Viewer.Caret.Line,
124 | StartChar = Viewer.Caret.Char,
125 | EndLine = Viewer.Caret.Line,
126 | EndChar = Viewer.Caret.Char,
127 | Text = "\r\n"
128 | };
129 | Operations.Push(operation);
130 | }
131 |
132 | public void ProcessDeletion(bool backward)
133 | {
134 | SaveCurrentOperationToStack();
135 |
136 | var start = Viewer.GetSelectionBoundary(true);
137 | var end = Viewer.GetSelectionBoundary(false);
138 | var operation = new UndoRedoOperation
139 | {
140 | Type = UndoRedoOperationType.Remove,
141 | StartLine = start.Line,
142 | StartChar = start.Char,
143 | EndLine = end.Line,
144 | EndChar = end.Char,
145 | };
146 | if (!Viewer.SelectionExists)
147 | {
148 | if (backward)
149 | operation.Text = Viewer.Caret.Char > 0 ? Doc[Viewer.Caret.Line].Text[Viewer.Caret.Char - 1].ToString() : "\r\n";
150 | else
151 | {
152 | if (Viewer.Caret.Char < Doc[Viewer.Caret.Line].Text.Length)
153 | operation.Text = Doc[Viewer.Caret.Line].Text[Viewer.Caret.Char].ToString();
154 | else
155 | operation.Text = "\r\n";
156 | }
157 | }
158 | else
159 | operation.Text = Viewer.SelectionText;
160 | Operations.Push(operation);
161 | }
162 |
163 | public void ProcessPaste(int startLine, int startChar, string text, string previousText)
164 | {
165 | SaveCurrentOperationToStack();
166 | var operation = new UndoRedoOperation
167 | {
168 | Type = UndoRedoOperationType.Paste,
169 | StartLine = startLine,
170 | StartChar = startChar,
171 | Text = text,
172 | EndLine = Caret.Line,
173 | EndChar = Caret.Char,
174 | PreviousText = previousText,
175 | };
176 | Operations.Push(operation);
177 | StartNewUndoRedoOperation();
178 | }
179 |
180 | public void ProcessCut()
181 | {
182 | SaveCurrentOperationToStack();
183 | var operation = TakeCurrentTypingOperation();
184 | operation.EndChar = Viewer.GetSelectionBoundary(false).Char;
185 | operation.Type = UndoRedoOperationType.Remove;
186 | operation.Text = Viewer.SelectionText;
187 | Operations.Push(operation);
188 | }
189 |
190 | private UndoRedoOperation SaveCurrentOperationToStack(bool cleanUndoneOperations = true)
191 | {
192 | UndoRedoOperation operation;
193 | if (CurrentStartChar != CurrentEndChar || CurrentStartLine != CurrentEndLine)
194 | {
195 | operation = TakeCurrentTypingOperation();
196 | Operations.Push(operation);
197 | }
198 | else
199 | operation = null;
200 |
201 | if (cleanUndoneOperations)
202 | UndoneOperations.Clear();
203 |
204 | StartNewUndoRedoOperation();
205 | return operation;
206 | }
207 |
208 | private void UndoTyping(UndoRedoOperation operation)
209 | {
210 | Doc[operation.StartLine].Text = Doc[operation.StartLine].Text.Remove(operation.StartChar, operation.EndChar - operation.StartChar);
211 | this.Viewer.Caret.MoveToPos(operation.StartLine, operation.StartChar, true);
212 | if (!string.IsNullOrEmpty(operation.PreviousText))
213 | EditingController.PasteText(operation.PreviousText);
214 | }
215 |
216 | private UndoRedoOperation TakeCurrentTypingOperation()
217 | {
218 | UndoRedoOperation operation;
219 | string text = Doc.GetText(CurrentStartLine, CurrentStartChar, CurrentEndLine, CurrentEndChar);
220 | operation = new UndoRedoOperation
221 | {
222 | StartLine = CurrentStartLine,
223 | StartChar = CurrentStartChar,
224 | EndLine = CurrentEndLine,
225 | EndChar = CurrentEndChar,
226 | Text = text,
227 | Type = UndoRedoOperationType.Insert,
228 | PreviousText = PreviousText
229 | };
230 | return operation;
231 | }
232 |
233 | private void StartNewUndoRedoOperation()
234 | {
235 | TextPoint startPoint = Viewer.GetSelectionBoundary(true);
236 | CurrentEndLine = CurrentStartLine = startPoint.Line;
237 | CurrentEndChar = CurrentStartChar = startPoint.Char;
238 |
239 | PreviousText = null;
240 | }
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/SA.CodeView.Tests/SampleData/SampleXml.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Technology
8 |
9 |
10 |
11 |
12 | TSQL
13 | SQL Server 2008 Transact-SQL
14 |
15 | ("ProductVers"="kbsqlserv105" AND "DevLang"="TSQL")
16 |
17 | ]]>
19 |
20 |
21 |
22 |
23 |
24 | kbMDX
25 | SQL Server 2008 Multidimensional Expressions (MDX)
26 |
27 | ("ProductVers"="kbsqlserv105" AND "DevLang"="kbMDX")
28 |
29 | ]]>
31 |
32 |
33 |
34 |
35 |
36 | DMX
37 | SQL Server 2008 Data Mining Extensions (DMX)
38 |
39 | ("ProductVers"="kbsqlserv105" AND "DevLang"="DMX")
40 |
41 | ]]>
43 |
44 |
45 |
46 |
47 |
48 | kbsqlserv105
49 | SQL Server 2008
50 |
51 | ("ProductVers"="kbsqlserv105")
52 |
53 | ]]>
55 |
56 |
57 |
58 |
59 |
60 | kbanalysisservices
61 | SQL Server 2008 Analysis Services
62 |
63 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbanalysisservices")
64 |
65 | ]]>
67 |
68 |
69 |
70 |
71 |
72 | kbdatamine
73 | SQL Server 2008 Data Mining
74 |
75 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbdatamine")
76 |
77 | ]]>
79 |
80 |
81 |
82 |
83 |
84 | kbdbengine
85 | SQL Server 2008 Database Engine
86 |
87 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbdbengine")
88 |
89 | ]]>
91 |
92 |
93 |
94 |
95 |
96 | kbdbengine
97 | SQL Server 2008 Express
98 |
99 | ("ProductVers"="sql10express")
100 |
101 | ]]>
103 |
104 |
105 |
106 |
107 |
108 |
109 | kbDTS
110 | SQL Server 2008 Integration Services
111 |
112 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbDTS")
113 |
114 | ]]>
116 |
117 |
118 |
119 |
120 |
121 | kbreplication
122 | SQL Server 2008 Replication
123 |
124 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbreplication")
125 |
126 | ]]>
128 |
129 |
130 |
131 |
132 |
133 | kbrepserv
134 | SQL Server 2008 Reporting Services
135 |
136 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbrepserv")
137 |
138 | ]]>
140 |
141 |
142 |
143 |
144 |
145 | kbMDS
146 | SQL Server Master Data Services
147 |
148 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbMDS")
149 |
150 | ]]>
152 |
153 |
154 |
155 |
156 |
157 | kbDAX
158 | SQL Server PowerPivot Data Analysis Expressions (DAX)
159 |
160 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbDAX")
161 |
162 | ]]>
164 |
165 |
166 |
167 |
168 |
169 | kbPowerPivot
170 | SQL Server PowerPivot for SharePoint
171 |
172 | ("ProductVers"="kbsqlserv105" AND "Technology"="kbPowerPivot")
173 |
174 | ]]>
176 |
177 |
178 |
179 |
180 |
181 |
182 |
--------------------------------------------------------------------------------
/SA.CodeView/CodeViewer/FindForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 |
5 | namespace SA.CodeView
6 | {
7 | public class FindForm : Form
8 | {
9 | private Label labelFind;
10 | private ComboBox comboFind;
11 | private GroupBox gbSearch;
12 | private CheckBox checkMatchWholeWord;
13 | private CheckBox checkMatchCase;
14 | private Button buttonFindNext;
15 | private Button buttonClose;
16 | //=========================================================================================
17 | #region Windows Form Designer generated code
18 |
19 | ///
20 | /// Required method for Designer support - do not modify
21 | /// the contents of this method with the code editor.
22 | ///
23 | private void InitializeComponent()
24 | {
25 | this.labelFind = new System.Windows.Forms.Label();
26 | this.comboFind = new System.Windows.Forms.ComboBox();
27 | this.gbSearch = new System.Windows.Forms.GroupBox();
28 | this.checkMatchWholeWord = new System.Windows.Forms.CheckBox();
29 | this.checkMatchCase = new System.Windows.Forms.CheckBox();
30 | this.buttonFindNext = new System.Windows.Forms.Button();
31 | this.buttonClose = new System.Windows.Forms.Button();
32 | this.gbSearch.SuspendLayout();
33 | this.SuspendLayout();
34 | //
35 | // labelFind
36 | //
37 | this.labelFind.AutoSize = true;
38 | this.labelFind.Location = new System.Drawing.Point(12, 18);
39 | this.labelFind.Name = "labelFind";
40 | this.labelFind.Size = new System.Drawing.Size(56, 13);
41 | this.labelFind.TabIndex = 0;
42 | this.labelFind.Text = "Find what:";
43 | //
44 | // comboFind
45 | //
46 | this.comboFind.FormattingEnabled = true;
47 | this.comboFind.Location = new System.Drawing.Point(74, 15);
48 | this.comboFind.Name = "comboFind";
49 | this.comboFind.Size = new System.Drawing.Size(256, 21);
50 | this.comboFind.TabIndex = 1;
51 | //
52 | // gbSearch
53 | //
54 | this.gbSearch.Controls.Add(this.checkMatchWholeWord);
55 | this.gbSearch.Controls.Add(this.checkMatchCase);
56 | this.gbSearch.Location = new System.Drawing.Point(15, 51);
57 | this.gbSearch.Name = "gbSearch";
58 | this.gbSearch.Size = new System.Drawing.Size(315, 63);
59 | this.gbSearch.TabIndex = 2;
60 | this.gbSearch.TabStop = false;
61 | this.gbSearch.Text = "Search";
62 | //
63 | // checkMatchWholeWord
64 | //
65 | this.checkMatchWholeWord.AutoSize = true;
66 | this.checkMatchWholeWord.Location = new System.Drawing.Point(6, 42);
67 | this.checkMatchWholeWord.Name = "checkMatchWholeWord";
68 | this.checkMatchWholeWord.Size = new System.Drawing.Size(113, 17);
69 | this.checkMatchWholeWord.TabIndex = 1;
70 | this.checkMatchWholeWord.Text = "Match whole word";
71 | this.checkMatchWholeWord.UseVisualStyleBackColor = true;
72 | //
73 | // checkMatchCase
74 | //
75 | this.checkMatchCase.AutoSize = true;
76 | this.checkMatchCase.Location = new System.Drawing.Point(6, 19);
77 | this.checkMatchCase.Name = "checkMatchCase";
78 | this.checkMatchCase.Size = new System.Drawing.Size(82, 17);
79 | this.checkMatchCase.TabIndex = 0;
80 | this.checkMatchCase.Text = "Match case";
81 | this.checkMatchCase.UseVisualStyleBackColor = true;
82 | //
83 | // buttonFindNext
84 | //
85 | this.buttonFindNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
86 | this.buttonFindNext.Location = new System.Drawing.Point(360, 13);
87 | this.buttonFindNext.Name = "buttonFindNext";
88 | this.buttonFindNext.Size = new System.Drawing.Size(75, 23);
89 | this.buttonFindNext.TabIndex = 3;
90 | this.buttonFindNext.Text = "Find Next";
91 | this.buttonFindNext.UseVisualStyleBackColor = true;
92 | //
93 | // buttonClose
94 | //
95 | this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
96 | this.buttonClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
97 | this.buttonClose.Location = new System.Drawing.Point(360, 89);
98 | this.buttonClose.Name = "buttonClose";
99 | this.buttonClose.Size = new System.Drawing.Size(75, 23);
100 | this.buttonClose.TabIndex = 4;
101 | this.buttonClose.Text = "Close";
102 | this.buttonClose.UseVisualStyleBackColor = true;
103 | //
104 | // FindForm
105 | //
106 | this.AcceptButton = this.buttonFindNext;
107 | this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
108 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
109 | this.CancelButton = this.buttonClose;
110 | this.ClientSize = new System.Drawing.Size(460, 125);
111 | this.Controls.Add(this.buttonClose);
112 | this.Controls.Add(this.buttonFindNext);
113 | this.Controls.Add(this.gbSearch);
114 | this.Controls.Add(this.comboFind);
115 | this.Controls.Add(this.labelFind);
116 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
117 | this.Name = "FindForm";
118 | this.ShowInTaskbar = false;
119 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
120 | this.Text = "Find";
121 | this.gbSearch.ResumeLayout(false);
122 | this.gbSearch.PerformLayout();
123 | this.ResumeLayout(false);
124 | this.PerformLayout();
125 |
126 | }
127 |
128 | #endregion
129 | //=========================================================================================
130 | TextFinder Finder;
131 | List ListSearch;
132 | //=========================================================================================
133 | public FindForm()
134 | {
135 | InitializeComponent();
136 | LinkHandlers();
137 | }
138 | //=========================================================================================
139 | private void LinkHandlers()
140 | {
141 | this.buttonFindNext.Click += new EventHandler(buttonFindNext_Click);
142 | this.buttonClose.Click += new EventHandler(buttonClose_Click);
143 | this.KeyDown += new KeyEventHandler(FindForm_KeyDown);
144 | this.FormClosing += new FormClosingEventHandler(FindForm_FormClosing);
145 | }
146 | //=========================================================================================
147 | public void Init(TextFinder finder, List listSearch)
148 | {
149 | this.Finder = finder;
150 | this.ListSearch = listSearch;
151 |
152 | if (this.ListSearch == null || this.ListSearch.Count == 0)
153 | return;
154 |
155 | this.comboFind.Items.AddRange(listSearch.ToArray());
156 | this.comboFind.SelectedIndex = 0;
157 | }
158 | //=========================================================================================
159 | void buttonFindNext_Click(object sender, EventArgs e)
160 | {
161 | if (!this.PrepareSearch())
162 | return;
163 |
164 | this.Finder.FindNext(this.comboFind.Text, this.checkMatchCase.Checked, this.checkMatchWholeWord.Checked);
165 | }
166 | //=========================================================================================
167 | void buttonClose_Click(object sender, EventArgs e)
168 | {
169 | this.Close();
170 | }
171 | //=========================================================================================
172 | void FindForm_KeyDown(object sender, KeyEventArgs e)
173 | {
174 | if (e.KeyCode == Keys.Escape)
175 | this.Close();
176 | }
177 | //=========================================================================================
178 | void FindForm_FormClosing(object sender, FormClosingEventArgs e)
179 | {
180 | if (this.ListSearch == null || this.comboFind.Items.Count == 0)
181 | return;
182 |
183 | this.ListSearch.Clear();
184 | foreach (string sItem in this.comboFind.Items)
185 | this.ListSearch.Add(sItem);
186 | }
187 | //=========================================================================================
188 | bool PrepareSearch()
189 | {
190 | if (this.Finder == null)
191 | return false;
192 |
193 | if (string.IsNullOrEmpty(comboFind.Text))
194 | return false;
195 |
196 | //Is there specified text in combobox items
197 | int iSelectedIndex = -1;
198 | for (int i = 0; i < this.comboFind.Items.Count; i++)
199 | if (string.Compare((string)this.comboFind.Items[i], this.comboFind.Text, false) == 0)
200 | {
201 | iSelectedIndex = i;
202 | break;
203 | }
204 |
205 | if (iSelectedIndex == -1)
206 | //add specified text to the list
207 | this.comboFind.Items.Insert(0, this.comboFind.Text);
208 | else if (iSelectedIndex > 0)
209 | {
210 | //make the text first in the list
211 | string sText = this.comboFind.Text;
212 | this.comboFind.Items.RemoveAt(iSelectedIndex);
213 | this.comboFind.Items.Insert(0, sText);
214 | this.comboFind.SelectedIndex = 0;
215 | }
216 |
217 | return true;
218 | }
219 | //=========================================================================================
220 | }
221 | }
222 |
--------------------------------------------------------------------------------