├── .gitignore ├── README.md ├── SA.CodeView.Tests ├── AssemblyInfo.cs ├── CodeViewing │ ├── EditorFeatures.cs │ ├── FontColorTests.cs │ └── RendererTests.cs ├── Editing │ ├── EditingTests.cs │ └── UndoRedoTests.cs ├── Entry.cs ├── IntelliSense │ ├── AutoCompleteTests.cs │ ├── BLL │ │ └── TestDbInfoProvider.cs │ ├── BasicTests.cs │ ├── CodeCompletorTests.cs │ ├── CodeCompletorTestsExtra.cs │ └── CodeViewerTokenIndexTests.cs ├── Parsing │ ├── MsSqlParsingTests.cs │ ├── NonSyntaxSettingsTests.cs │ ├── ParsingOnElements │ │ └── ParserTests.cs │ ├── StateParserTests.cs │ ├── StateScannerTests.cs │ ├── SyntaxSettingsTests.cs │ └── XmlParsingTests.cs ├── SA.CodeView.Tests.csproj ├── SampleData │ ├── MsSql_1Mb.sql │ └── SampleXml.xml ├── TestForms │ ├── StartForm.cs │ └── StartForm.resx ├── app.config └── packages.config ├── SA.CodeView.sln ├── SA.CodeView ├── AssemblyInfo.cs ├── Coco │ ├── Parser.frame │ └── Scanner.frame ├── CodeViewer │ ├── CodeViewer.cs │ ├── CodeViewerBody.cs │ ├── CodeViewerBody.resx │ ├── Document.cs │ ├── DocumentViewRenderer.cs │ ├── FindForm.cs │ ├── FindForm.resx │ ├── SmallTypes.cs │ ├── TextCaret.cs │ ├── TextFinder.cs │ ├── TextPoint.cs │ ├── TextSpan.cs │ └── TextStyle.cs ├── Editing │ ├── ClipboardProxyClass.cs │ ├── EditingController.cs │ ├── UndoRedoManager.cs │ └── UndoRedoOperation.cs ├── IntelliSense │ ├── CodeCompletor.cs │ ├── CompletionVariant.cs │ ├── DbInfoProvider │ │ └── DbInfoProvider.cs │ ├── EditQueryRegExBuilder.cs │ ├── SuggestionBuilder.cs │ ├── Visual │ │ ├── Icons │ │ │ ├── column.bmp │ │ │ ├── db.bmp │ │ │ ├── schema.bmp │ │ │ └── table.bmp │ │ ├── IntelliSenseListView.cs │ │ ├── IntellisenseForm.Designer.cs │ │ ├── IntellisenseForm.cs │ │ ├── IntellisenseForm.resx │ │ ├── IntellisenseMessageFilter.cs │ │ └── WinApi.cs │ └── WhereSuggestionBuilder.cs ├── Languages │ ├── CSharpSyntaxSettings.cs │ ├── Enums.cs │ ├── MsSqlSyntaxSettings.cs │ ├── MySqlSyntaxSettings.cs │ ├── NonSyntaxSettings.cs │ ├── OracleSyntaxSettings.cs │ ├── SyntaxSettings.cs │ ├── VisualBasicSyntaxSettings.cs │ └── XmlSyntaxSettings.cs ├── Parsing │ ├── BufferReader.cs │ ├── ISyntaxParser.cs │ ├── Literal.cs │ ├── ParserSpecification.cs │ ├── ParsingOnElements (obsolete) │ │ ├── BaseElement.cs │ │ ├── BoundedElement.cs │ │ ├── Enums.cs │ │ ├── FixedListElement.cs │ │ ├── Sequence.cs │ │ ├── SingleElement.cs │ │ └── SyntaxParser.cs │ ├── RuleDefParsing │ │ ├── Grammar.atg │ │ ├── Parser.HandMade.cs │ │ ├── Parser.cs │ │ ├── Scanner.cs │ │ └── coc.bat │ ├── ScannerSpecification.cs │ ├── StateParser.cs │ ├── StateParserState.cs │ ├── StateScanner.cs │ ├── StateScannerState.cs │ ├── Token.cs │ └── TokenDefParsing │ │ ├── Grammar.atg │ │ ├── Parser.HandMade.cs │ │ ├── Parser.cs │ │ ├── Scanner.cs │ │ └── coc.bat ├── SA.CodeView.csproj └── Utils │ ├── TextSplitter.cs │ └── WordFinder.cs └── Screenshots ├── current-line-highlihting.png ├── find-window.png ├── spans-sample.png └── syntax-highlighting.png /.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 | -------------------------------------------------------------------------------- /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 | ![ShowFind window](https://github.com/ygavrishov/SA.CodeView/blob/master/Screenshots/find-window.png) 19 | 20 | * **Current line highlighting**. Turn on HighlightCurrentLine property. 21 | 22 | ![Current line highlighting](https://github.com/ygavrishov/SA.CodeView/blob/master/Screenshots/current-line-highlihting.png) 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 | ![Spans sample](https://github.com/ygavrishov/SA.CodeView/blob/master/Screenshots/spans-sample.png) 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 | ![Syntax highlighting](https://github.com/ygavrishov/SA.CodeView/blob/master/Screenshots/syntax-highlighting.png) 38 | 39 | or implement your own implementation. 40 | -------------------------------------------------------------------------------- /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.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/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.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.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.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.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.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.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.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/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.Tests/Parsing/ParsingOnElements/ParserTests.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView.Tests/Parsing/ParsingOnElements/ParserTests.cs -------------------------------------------------------------------------------- /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/Parsing/StateScannerTests.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView.Tests/Parsing/StateScannerTests.cs -------------------------------------------------------------------------------- /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.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", ""); 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.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.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.Tests/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SA.CodeView.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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/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/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/Coco/Scanner.frame: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/Coco/Scanner.frame -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/CodeViewer/TextCaret.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/CodeViewer/TextCaret.cs -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/IntelliSense/Visual/Icons/column.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/IntelliSense/Visual/Icons/column.bmp -------------------------------------------------------------------------------- /SA.CodeView/IntelliSense/Visual/Icons/db.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/IntelliSense/Visual/Icons/db.bmp -------------------------------------------------------------------------------- /SA.CodeView/IntelliSense/Visual/Icons/schema.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/IntelliSense/Visual/Icons/schema.bmp -------------------------------------------------------------------------------- /SA.CodeView/IntelliSense/Visual/Icons/table.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/IntelliSense/Visual/Icons/table.bmp -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/Languages/SyntaxSettings.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/Languages/SyntaxSettings.cs -------------------------------------------------------------------------------- /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/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/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/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/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/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)/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 | -------------------------------------------------------------------------------- /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/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)/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/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/Parsing/ParsingOnElements (obsolete)/SyntaxParser.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/Parsing/ParsingOnElements (obsolete)/SyntaxParser.cs -------------------------------------------------------------------------------- /SA.CodeView/Parsing/RuleDefParsing/Grammar.atg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/Parsing/RuleDefParsing/Grammar.atg -------------------------------------------------------------------------------- /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/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/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/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/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/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/TokenDefParsing/Grammar.atg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/SA.CodeView/Parsing/TokenDefParsing/Grammar.atg -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /Screenshots/current-line-highlihting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/Screenshots/current-line-highlihting.png -------------------------------------------------------------------------------- /Screenshots/find-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/Screenshots/find-window.png -------------------------------------------------------------------------------- /Screenshots/spans-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/Screenshots/spans-sample.png -------------------------------------------------------------------------------- /Screenshots/syntax-highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ygavrishov/SA.CodeView/67e90c1e19485dc2e926f35a1e460aa059d162a7/Screenshots/syntax-highlighting.png --------------------------------------------------------------------------------