Sfall-ScriptEditor

Форк
0
/
TextEditor.Utils.cs 
1093 строки · 47.6 Кб
1
using System;
2
using System.Collections.Generic;
3
using System.Drawing;
4
using System.IO;
5
using System.Linq;
6
using System.Text.RegularExpressions;
7
using System.Windows.Forms;
8

9
using ICSharpCode.TextEditor;
10
using ICSharpCode.TextEditor.Document;
11

12
using ScriptEditor.CodeTranslation;
13
using ScriptEditor.TextEditorUI;
14
using ScriptEditor.TextEditorUtilities;
15

16
using ScriptEditor.SyntaxRules;
17

18
namespace ScriptEditor
19
{
20
    partial class TextEditor
21
    {
22
        #region Search Function
23
        private bool SubSearchInternal(List<int> offsets, List<int> lengths)
24
        {
25
            AddSearchTextComboBox(sf.cbSearch.Text);
26

27
            RegexOptions option = RegexOptions.None;
28
            Regex regex = null;
29

30
            if (!sf.cbCase.Checked) option = RegexOptions.IgnoreCase;
31

32
            if (sf.cbRegular.Checked)
33
                regex = new Regex(sf.cbSearch.Text, option);
34
            else if (Settings.searchWholeWord)
35
                regex = new Regex(@"\b" + sf.cbSearch.Text + @"\b", option);
36

37
            if (sf.rbFolder.Checked && (Settings.lastSearchPath == null || !Directory.Exists(Settings.lastSearchPath))) {
38
                MessageBox.Show("No search path set.", "Error");
39
                return false;
40
            }
41
            if (!sf.cbFindAll.Checked) {
42
                if (sf.rbCurrent.Checked || (sf.rbAll.Checked && tabs.Count < 2)) {
43
                    if (currentTab == null)
44
                        return false;
45
                    if (Utilities.SearchAndScroll(currentActiveTextAreaCtrl, regex, sf.cbSearch.Text, sf.cbCase.Checked, ref PosChangeType))
46
                        return true;
47
                } else if (sf.rbAll.Checked) {
48
                    int starttab = currentTab == null ? 0 : currentTab.index;
49
                    int endtab = starttab == 0 ? tabs.Count - 1 : starttab - 1;
50
                    int tab = starttab - 1;
51
                    int caretOffset = currentActiveTextAreaCtrl.Caret.Offset;
52
                    do {
53
                        if (++tab == tabs.Count)
54
                            tab = 0; //restart tab
55
                        int start, len;
56
                        if (Utilities.Search(tabs[tab].textEditor.Text, sf.cbSearch.Text, regex, caretOffset + 1, false, sf.cbCase.Checked, out start, out len)) {
57
                            Utilities.FindSelected(tabs[tab].textEditor.ActiveTextAreaControl, start, len, ref PosChangeType);
58
                            if (currentTab == null || currentTab.index != tab)
59
                                tabControl1.SelectTab(tab);
60
                            return true;
61
                        }
62
                        caretOffset = 0; // search from begin
63
                    } while (tab != endtab);
64
                } else {
65
                    sf.lbFindFiles.Items.Clear();
66
                    sf.lbFindFiles.Tag = regex;
67
                    List<string> files = sf.GetFolderFiles();
68
                    ProgressBarForm progress = new ProgressBarForm(this, files.Count, "Search matches...");
69
                    for (int i = 0; i < files.Count; i++)
70
                    {
71
                        if (Utilities.Search(File.ReadAllText(files[i]), sf.cbSearch.Text, regex, sf.cbCase.Checked))
72
                            sf.lbFindFiles.Items.Add(files[i]);
73
                        progress.SetProgress = i;
74
                    }
75
                    progress.Dispose();
76
                    sf.labelCount.Text = sf.lbFindFiles.Items.Count.ToString();
77
                    if (sf.lbFindFiles.Items.Count > 0) {
78
                        if (sf.Height < 500) sf.Height = 500;
79
                        return true;
80
                    }
81
                }
82
            } else {
83
                DataGridView dgv = CommonDGV.DataGridCreate();
84
                dgv.DoubleClick += dgvErrors_DoubleClick;
85

86
                if (sf.rbCurrent.Checked || (sf.rbAll.Checked && tabs.Count < 2)) {
87
                    if (currentTab == null)
88
                        return false;
89
                    Utilities.SearchForAll(currentTab, sf.cbSearch.Text, regex, sf.cbCase.Checked, dgv, offsets, lengths);
90
                } else if (sf.rbAll.Checked) {
91
                    for (int i = 0; i < tabs.Count; i++)
92
                        Utilities.SearchForAll(tabs[i], sf.cbSearch.Text, regex, sf.cbCase.Checked, dgv, offsets, lengths);
93
                } else {
94
                    List<string> files = sf.GetFolderFiles();
95
                    ProgressBarForm progress = new ProgressBarForm(this, files.Count, "Search matches...");
96
                    for (int i = 0; i < files.Count; i++) {
97
                        Utilities.SearchForAll(File.ReadAllLines(files[i]), Path.GetFullPath(files[i]), sf.cbSearch.Text, regex, sf.cbCase.Checked, dgv);
98
                        progress.SetProgress = i;
99
                    }
100
                    progress.Dispose();
101
                }
102
                if (dgv.RowCount > 0) {
103
                    TabPage tp = new TabPage("Search results");
104
                    tp.ToolTipText = "Find text: " + sf.cbSearch.Text;
105
                    tp.Controls.Add(dgv);
106
                    dgv.Dock = DockStyle.Fill;
107
                    tabControl2.TabPages.Add(tp);
108
                    tabControl2.SelectTab(tp);
109
                    MaximizeLog();
110
                    return true;
111
                }
112
            }
113
            MessageBox.Show("Search string not found", "Search");
114
            return false;
115
        }
116
        #endregion
117

118
        #region Search & Replace function form
119
        private string lastSearchText = string.Empty;
120

121
        private void findToolStripMenuItem_Click(object sender, EventArgs e)
122
        {
123
            string searchText = lastSearchText;
124
            if (sf == null) {
125
                sf = new SearchForm();
126
                sf.Owner = this;
127

128
                sf.FormClosed += delegate(object a1, FormClosedEventArgs a2) {
129
                    lastSearchText = sf.cbSearch.Text;
130
                    sf = null;
131
                };
132

133
                sf.lbFindFiles.MouseDoubleClick += delegate (object a1, MouseEventArgs a2) {
134
                    if (sf.lbFindFiles.Items.Count == 0) return;
135

136
                    string file = sf.lbFindFiles.SelectedItem.ToString();
137

138
                    TabInfo tab = CheckTabs(tabs, file); // проверить открыт ли уже этот файл
139
                    bool isOpen = (tab != null);
140
                    if (!isOpen) tab = Open(file, OpenType.File, false);
141

142
                    Utilities.SearchAndScroll(tab.textEditor.ActiveTextAreaControl, (Regex)sf.lbFindFiles.Tag,
143
                                              sf.cbSearch.Text, sf.cbCase.Checked, ref PosChangeType, false);
144

145
                    if (isOpen) SwitchToTab(tab.index);
146
                };
147

148
                sf.bSearch.Click += new EventHandler(bSearch_Click);
149
                sf.bReplace.Click += new EventHandler(bReplace_Click);
150

151
                sf.cbSearch.Items.AddRange(SearchTextComboBox.Items.Cast<String>().ToArray());
152
            } else {
153
                sf.WindowState = FormWindowState.Normal;
154
                sf.Focus();
155

156
                searchText = sf.cbSearch.Text;
157
            }
158

159
            if (currentTab != null && currentActiveTextAreaCtrl.SelectionManager.HasSomethingSelected) {
160
                searchText = currentActiveTextAreaCtrl.SelectionManager.SelectedText;
161
            }
162
            if (searchText.Length == 0) {
163
                searchText = Clipboard.GetText();
164
            }
165
            if (searchText.Length > 0 && searchText.Length < 255) {
166
                sf.cbSearch.Text = searchText;
167
            }
168
            sf.Show();
169
            sf.cbSearch.Focus();
170
            sf.cbSearch.SelectAll();
171
        }
172

173
        private void bSearch_Click(object sender, EventArgs e)
174
        {
175
            sf.cbSearch.Text = sf.cbSearch.Text.Trim();
176
            if (sf.cbSearch.Text.Length == 0)
177
                return;
178
            SubSearchInternal(null, null);
179
        }
180

181
        void bReplace_Click(object sender, EventArgs e)
182
        {
183
            sf.cbSearch.Text = sf.cbSearch.Text.Trim();
184
            if (sf.rbFolder.Checked || sf.cbSearch.Text.Length == 0)
185
                return;
186
            if (sf.cbFindAll.Checked) {
187
                List<int> lengths = new List<int>(), offsets = new List<int>();
188
                if (!SubSearchInternal(offsets, lengths))
189
                    return;
190
                for (int i = offsets.Count - 1; i >= 0; i--)
191
                {
192
                    currentDocument.Replace(offsets[i], lengths[i], sf.tbReplace.Text);
193
                }
194
            } else {
195
                currentActiveTextAreaCtrl.Caret.Column--;
196
                if (!SubSearchInternal(null, null))
197
                    return;
198
                ISelection selected = currentActiveTextAreaCtrl.SelectionManager.SelectionCollection[0];
199
                currentDocument.Replace(selected.Offset, selected.Length, sf.tbReplace.Text);
200
                selected.EndPosition = new TextLocation(selected.StartPosition.Column + sf.tbReplace.Text.Length, selected.EndPosition.Line);
201
                currentActiveTextAreaCtrl.SelectionManager.SetSelection(selected);
202
            }
203
        }
204

205
        // Search for quick panel
206
        private void FindForwardButton_Click(object sender, EventArgs e)
207
        {
208
            string find = SearchTextComboBox.Text.Trim();
209
            if (find.Length == 0 || currentTab == null)
210
                return;
211
            int z = Utilities.SearchPanel(currentTab.textEditor.Text, find, currentActiveTextAreaCtrl.Caret.Offset + 1,
212
                                            CaseButton.Checked, WholeWordButton.Checked);
213
            if (z != -1)
214
                Utilities.FindSelected(currentActiveTextAreaCtrl, z, find.Length, ref PosChangeType);
215
            else
216
                DontFind.Play();
217
            AddSearchTextComboBox(find);
218
        }
219

220
        private void FindBackButton_Click(object sender, EventArgs e)
221
        {
222
            string find = SearchTextComboBox.Text.Trim();
223
            if (find.Length == 0 || currentTab == null)
224
                return;
225
            int offset = currentActiveTextAreaCtrl.Caret.Offset;
226
            string text = currentTab.textEditor.Text.Remove(offset);
227
            int z = Utilities.SearchPanel(text, find, offset - 1, CaseButton.Checked, WholeWordButton.Checked, true);
228
            if (z != -1)
229
                Utilities.FindSelected(currentActiveTextAreaCtrl, z, find.Length, ref PosChangeType);
230
            else
231
                DontFind.Play();
232
            AddSearchTextComboBox(find);
233
        }
234

235
        private void ReplaceButton_Click(object sender, EventArgs e)
236
        {
237
            string find = SearchTextComboBox.Text.Trim();
238
            if (find.Length == 0)
239
                return;
240
            string replace = ReplaceTextBox.Text.Trim();
241
            int z = Utilities.SearchPanel(currentTab.textEditor.Text, find, currentActiveTextAreaCtrl.Caret.Offset,
242
                                            CaseButton.Checked, WholeWordButton.Checked);
243
            if (z != -1)
244
                Utilities.FindSelected(currentActiveTextAreaCtrl, z, find.Length, ref PosChangeType, replace);
245
            else
246
                DontFind.Play();
247
            AddSearchTextComboBox(find);
248
        }
249

250
        private void ReplaceAllButton_Click(object sender, EventArgs e)
251
        {
252
            string find = SearchTextComboBox.Text.Trim();
253
            if (find.Length == 0)
254
                return;
255

256
            string replace = ReplaceTextBox.Text.Trim();
257
            int z, offset = 0;
258
            do {
259
                z = Utilities.SearchPanel(currentTab.textEditor.Text, find, offset,
260
                                            CaseButton.Checked, WholeWordButton.Checked);
261
                if (z != -1)
262
                    currentActiveTextAreaCtrl.Document.Replace(z, find.Length, replace);
263
                offset = z + 1;
264
            } while (z != -1);
265
            AddSearchTextComboBox(find);
266
        }
267

268
        private void SendtoolStripButton_Click(object sender, EventArgs e)
269
        {
270
            string word = currentActiveTextAreaCtrl.SelectionManager.SelectedText;
271
            if (word == string.Empty)
272
                word = TextUtilities.GetWordAt(currentDocument, currentActiveTextAreaCtrl.Caret.Offset);
273
            if (word != string.Empty)
274
                SearchTextComboBox.Text = word;
275
        }
276

277
        private void quickFindToolStripMenuItem_Click(object sender, EventArgs e)
278
        {
279
            if (currentTab == null)
280
                return;
281

282
            SendtoolStripButton.PerformClick();
283
            FindForwardButton.PerformClick();
284
            if (!SearchToolStrip.Visible) {
285
                SearchToolStrip.Visible = true;
286
                TabClose_button.Top += (SearchToolStrip.Visible) ? 25 : -25;
287
            }
288
        }
289

290
        private void Search_Panel(object sender, EventArgs e)
291
        {
292
            if (currentTab == null && !SearchToolStrip.Visible) {
293
                findToolStripMenuItem_Click(null, null);
294
                return;
295
            }
296
            SearchToolStrip.Visible = !SearchToolStrip.Visible;
297
            TabClose_button.Top += (SearchToolStrip.Visible) ? 25 : -25;
298
        }
299
        #endregion
300

301
        #region References/Decleration/Definition & Include function
302
        private void findReferencesToolStripMenuItem_Click(object sender, EventArgs e)
303
        {
304
            TextLocation tl = currentActiveTextAreaCtrl.Caret.Position; //(TextLocation)editorMenuStrip.Tag;
305
            string word = TextUtilities.GetWordAt(currentDocument, currentDocument.PositionToOffset(tl));
306

307
            Reference[] refs = currentTab.parseInfo.LookupReferences(word, currentTab.filepath, tl.Line);
308
            if (refs == null)
309
                return;
310
            if (refs.Length == 0) {
311
                MessageBox.Show("No references found", "Reference", MessageBoxButtons.OK, MessageBoxIcon.Information);
312
                return;
313
            }
314
            DataGridView dgv = CommonDGV.DataGridCreate();
315
            dgv.DoubleClick += dgvErrors_DoubleClick;
316

317
            int lastLine = 0, nextColumn = 0;
318
            foreach (var r in refs)
319
            {
320
                if (lastLine != r.line) nextColumn = 0; 
321
                Error error = new Error(ErrorType.Search) {
322
                    fileName = r.file,
323
                    line = r.line,
324
                    column = TextUtilities.GetLineAsString(currentDocument, r.line - 1).IndexOf(word, nextColumn, StringComparison.OrdinalIgnoreCase),
325
                    len = word.Length,
326
                    message = (String.Compare(Path.GetFileName(r.file), currentTab.filename, true) == 0)
327
                               ? TextUtilities.GetLineAsString(currentDocument, r.line - 1).TrimStart()
328
                               : "< Preview is not possible: for viewing goto this the reference link >"
329
                };
330
                lastLine = r.line;
331
                nextColumn = error.column + word.Length;
332
                if (error.column > 0)
333
                    error.column++;
334
                dgv.Rows.Add(r.file, r.line, error);
335
            }
336

337
            TabPage tp = new TabPage("'" + word + "' references");
338
            tp.Controls.Add(dgv);
339
            dgv.Dock = DockStyle.Fill;
340
            tabControl2.TabPages.Add(tp);
341
            tabControl2.SelectTab(tp);
342
            MaximizeLog();
343
            TextArea_SetFocus(null, null);
344
        }
345

346
        private void findDeclerationToolStripMenuItem_Click(object sender, EventArgs e)
347
        {
348
            TextLocation tl = currentActiveTextAreaCtrl.Caret.Position; //(TextLocation)editorMenuStrip.Tag;
349
            string word = TextUtilities.GetWordAt(currentDocument, currentDocument.PositionToOffset(tl));
350
            string file;
351
            int line;
352
            currentTab.parseInfo.LookupDecleration(word, currentTab.filepath, tl.Line, out file, out line);
353
            SelectLine(file, line);
354
        }
355

356
        private void findDefinitionToolStripMenuItem_Click(object sender, EventArgs e)
357
        {
358
            if (currentTab == null) return;
359

360
            string word, file = currentTab.filepath;
361
            int line;
362
            TextLocation tl = currentActiveTextAreaCtrl.Caret.Position;
363
            if (((ToolStripDropDownItem)sender).Tag != null) { // for "Button"
364
                if (!currentTab.shouldParse)
365
                    return;
366

367
                ParserInternal.UpdateParseBuffer(currentTab.textEditor.Text);
368

369
                word = TextUtilities.GetWordAt(currentDocument, currentDocument.PositionToOffset(tl));
370
                line = ParserInternal.GetProcedureBlock(word, 0, true).begin;
371
                if (line != -1)
372
                    line++;
373
                else
374
                    return;
375
            } else {
376
                //TextLocation tl = (TextLocation)editorMenuStrip.Tag;
377
                word = TextUtilities.GetWordAt(currentDocument, currentDocument.PositionToOffset(tl));
378
                currentTab.parseInfo.LookupDefinition(word, out file, out line);
379
            }
380
            SelectLine(file, line);
381
        }
382

383
        private void openIncludeToolStripMenuItem_Click(object sender, EventArgs e)
384
        {
385
            TextLocation tl = currentActiveTextAreaCtrl.Caret.Position; //(TextLocation)editorMenuStrip.Tag;
386
            string[] line = TextUtilities.GetLineAsString(currentDocument, tl.Line).Split('"');
387
            if (line.Length < 2)
388
                return;
389

390
            if (!Settings.searchIncludePath && currentTab.filepath == null && !Path.IsPathRooted(line[1])) {
391
                MessageBox.Show("Cannot open includes given via a relative path for an unsaved script", "Error");
392
                return;
393
            }
394
            if (line[1].IndexOfAny(Path.GetInvalidPathChars()) != -1) return;
395
            ParserInternal.GetIncludePath(ref line[1], Path.GetDirectoryName(currentTab.filepath));
396
            if (Open(line[1], OpenType.File, false) == null)
397
                MessageBox.Show("Header file not found!\n" + line[1], null, MessageBoxButtons.OK, MessageBoxIcon.Stop);
398
        }
399

400
        private void renameToolStripMenuItem_Click(object sender, EventArgs e)
401
        {
402
            Refactor.Rename((IParserInfo)renameToolStripMenuItem.Tag, currentDocument, currentTab, tabs);
403
        }
404
        #endregion
405

406
        #region Autocomplete and tips function control
407
        private void TextArea_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
408
        {
409
            //PosChangeType = PositionType.OverridePos; // Save position change for navigation, if key was pressed
410

411
            if (e.KeyCode == Keys.Enter) updateHighlightPocedure = false;
412

413
            if (autoComplete.IsVisible) {
414
                autoComplete.TA_PreviewKeyDown(e);
415
                if (Settings.autocomplete && e.KeyCode == Keys.Back) {
416
                    autoComplete.GenerateList(String.Empty, currentTab,
417
                        currentActiveTextAreaCtrl.Caret.Offset - 1, toolTips.Tag, true);
418
                }
419
            }
420
            if (toolTips.Active) {
421
                if (e.KeyCode == Keys.Up || (e.KeyCode == Keys.Down && !autoComplete.IsVisible)
422
                    || e.KeyCode == Keys.Enter || e.KeyCode == Keys.Escape
423
                    || (toolTips.Tag != null && !(bool)toolTips.Tag)) {
424
                        ToolTipsHide();
425
                }
426
                else if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Right) {
427
                    int caret = currentActiveTextAreaCtrl.Caret.Offset;
428
                    int offset = caret;
429
                    if (e.KeyCode == Keys.Left)
430
                        caret--;
431
                    else {
432
                        caret++;
433
                        offset = TextUtilities.SearchBracketForward(currentDocument, showTipsColumn + 1, '(', ')');
434
                    }
435
                    if (showTipsColumn >= caret || caret > offset) ToolTipsHide();
436
                }
437
            }
438
            if (e.KeyCode == Keys.Tab) { // Закрытие списка, если нажата клавиша таб после ключевого слова
439
                if (Utilities.AutoCompleteKeyWord(currentActiveTextAreaCtrl)) {
440
                    e.IsInputKey = true;
441
                    autoComplete.ShiftCaret = false;
442
                    if (autoComplete.IsVisible)
443
                        autoComplete.Close();
444
                }
445
            }
446
        }
447

448
        private void VScrollBar_ValueChanged(object sender, EventArgs e)
449
        {
450
            autoComplete.TA_MouseScroll(currentTab.textEditor.ActiveTextAreaControl);
451
            if (toolTips.Active) ToolTipsHide();
452
        }
453

454
        private void ToolTipsHide()
455
        {
456
            if (autoComplete.IsVisible && (bool)toolTips.Tag)
457
                autoComplete.Close();
458

459
            toolTips.Hide(panel1);
460
            toolTips.Tag = toolTips.Active = false;
461
        }
462

463
        private void TextEditor_KeyDown(object sender, KeyEventArgs e)
464
        {
465
            if (e.KeyCode == Keys.ControlKey) {
466
                autoComplete.Hide();
467
                ctrlKeyPress = true;
468
            }
469
        }
470

471
        private void TextEditor_KeyUp(object sender, KeyEventArgs e)
472
        {
473
            if (e.KeyCode == Keys.ControlKey) {
474
                autoComplete.UnHide();
475
                ctrlKeyPress = false;
476
            }
477
        }
478

479
        private void showAutocompleteWordToolStripMenuItem_Click(object sender, EventArgs e)
480
        {
481
            if (currentTab != null && Settings.autocomplete) {
482
                Caret caret = currentActiveTextAreaCtrl.Caret;
483
                if (!ColorTheme.CheckColorPosition(currentDocument, caret.Position))
484
                    autoComplete.GenerateList(String.Empty, currentTab, caret.Offset, null);
485
            }
486
        }
487

488
        //
489
        private void ShowCodeTips(string tipText, Caret caret, int duration, bool tag = false)
490
        {
491
            int offset = TextUtilities.FindWordStart(currentDocument, caret.Offset - 1);
492
            offset = caret.Offset - offset;
493
            Point pos = caret.GetScreenPosition(caret.Line, caret.Column - offset);
494
            pos.Offset(currentActiveTextAreaCtrl.FindForm().PointToClient(
495
                       currentActiveTextAreaCtrl.Parent.PointToScreen(currentActiveTextAreaCtrl.Location)));
496
            offset = (autoComplete.IsVisible) ? -25 : 20;
497
            pos.Offset(0, offset);
498

499
            if (tag) showTipsColumn = caret.Offset;
500

501
            toolTips.Active = true;
502
            toolTips.Tag = tag;
503
            toolTips.Show(tipText, panel1, pos, duration);
504
        }
505

506
        private int  inputPairedBrackets = 0;
507
        private char keyPressChar;
508

509
        private void TextArea_KeyPressed(object sender, KeyPressEventArgs e)
510
        {
511
            keyPressChar = e.KeyChar;
512
            var caret = currentActiveTextAreaCtrl.Caret;
513

514
            if (Settings.autoInputPaired && e.KeyChar == '"') {
515
                List<Utilities.Quote> quotes = new  List<Utilities.Quote>();
516
                Utilities.GetQuotesPosition(TextUtilities.GetLineAsString(currentDocument, caret.Line), quotes);
517
                // skiping quotes "..." region
518
                bool inQuotes = false;
519
                foreach (Utilities.Quote q in quotes)
520
                {
521
                    if (caret.Column > q.Open && caret.Column < q.Close) {
522
                        inQuotes = true;
523
                        break;
524
                    }
525
                }
526
                if (!inQuotes) {
527
                    char chR = currentDocument.GetCharAt(caret.Offset);
528
                    char chL = currentDocument.GetCharAt(caret.Offset - 1);
529
                    if ((chL == '(' && chR == ')') || (chL != '"' && (chR == ' ' || chR == '\r') && !Char.IsLetterOrDigit(chL)))
530
                        currentDocument.Insert(caret.Offset, "\"");
531
                    else if (chL == '"' && chR == '"')
532
                        currentDocument.Remove(caret.Offset, 1);
533
                }
534
            }
535
            else if (e.KeyChar == '(' || e.KeyChar == '[' || e.KeyChar == '{') {
536
                if (autoComplete.IsVisible) autoComplete.Close();
537
                if (e.KeyChar == '{') return;
538

539
                if (Settings.showTips && currentTab.parseInfo != null && e.KeyChar == '(') {
540
                    string word = TextUtilities.GetWordAt(currentDocument, caret.Offset - 1);
541
                    if (word != String.Empty) {
542
                        string item = ProgramInfo.LookupOpcodesToken(word);
543
                        if (item != null) {
544
                            int z = item.IndexOf('\n');
545
                            if (z > 0)
546
                                item = item.Remove(z);
547
                        }
548
                        if (item == null)
549
                            item = currentTab.parseInfo.LookupToken(word, null, 0, true);
550
                        if (item != null)
551
                            ShowCodeTips(item, caret, 50000, true);
552
                    }
553
                }
554

555
                if (Settings.autoInputPaired && Char.IsWhiteSpace(currentDocument.GetCharAt(caret.Offset))) {
556
                    inputPairedBrackets = 2;
557
                    string bracket = (e.KeyChar == '[') ? "]" : ")";
558
                    currentDocument.Insert(caret.Offset, bracket);
559
                }
560
            } else if (e.KeyChar == ')' || e.KeyChar == ']' || e.KeyChar == '}') {
561
                if (toolTips.Active) ToolTipsHide();
562
                if (e.KeyChar == '}') return;
563

564
                if (Settings.autoInputPaired && inputPairedBrackets > 0) {
565
                    char bracket = (e.KeyChar == ']') ? '[' : '(';
566
                    if (currentDocument.GetCharAt(caret.Offset -1) == bracket && currentDocument.GetCharAt(caret.Offset) == e.KeyChar) {
567
                        currentDocument.Remove(caret.Offset, 1);
568
                        // TODO BUG: В контроле баг при использовании TextBuffer - стирается строка символов.
569
                        //currentDocument.TextBufferStrategy.Remove(caret.Offset, 1);
570
                        //currentActiveTextAreaCtrl.TextArea.Refresh();
571
                    }
572
                }
573
            } else {
574
                if (Settings.autocomplete) {
575
                    if (!ColorTheme.CheckColorPosition(currentDocument, caret.Position))
576
                        autoComplete.GenerateList(e.KeyChar.ToString(), currentTab, caret.Offset - 1, toolTips.Tag);
577
                }
578
            }
579
            if (inputPairedBrackets > 0) inputPairedBrackets--;
580
        }
581

582
        void TextArea_KeyUp(object sender, KeyEventArgs e)
583
        {
584
            if (!currentTab.shouldParse) return;
585
            updateHighlightPocedure = true;
586

587
            if (e.KeyCode == Keys.OemSemicolon && keyPressChar == ';') Utilities.FormattingCodeSmart(currentActiveTextAreaCtrl);
588

589
            if (!Settings.showTips || toolTips.Active || !Char.IsLetter(Convert.ToChar(e.KeyValue))) return;
590

591
            var caret = currentActiveTextAreaCtrl.Caret;
592
            string word = TextUtilities.GetWordAt(currentDocument, caret.Offset - 1);
593
            if (word != String.Empty) {
594
                switch (word) {
595
                    case "for":
596
                    case "foreach":
597
                    case "while":
598
                    case "switch":
599
                    case "if":
600
                    case "ifel":
601
                    case "elif":
602
                        ShowCodeTips("Press the TAB key to insert the autocode.", caret, 5000);
603
                        break;
604
                }
605
            }
606
        }
607
        #endregion
608

609
        #region Navigation Back/Forward
610
        /*
611
         * AddPos       - Добавлять в историю новую позицию перемещения.
612
         * NoStore      - Не сохранять следующее перемещение в историю.
613
         * OverridePos  - Перезаписать позицию перемещения в текущей позиции истории.
614
         * Disabled     - Не сохранять все последуюшие перемещения в историю (до явного включения функции).
615
         */
616
        internal enum PositionType { AddPos, NoStore, OverridePos, Disabled }
617

618
        private void SetBackForwardButtonState()
619
        {
620
            if (currentTab.history.pointerCur > 0)
621
                Back_toolStripButton.Enabled = true;
622
            else
623
                Back_toolStripButton.Enabled = false;
624

625
            if (currentTab.history.pointerCur == currentTab.history.pointerEnd || currentTab.history.pointerCur < 0)
626
                Forward_toolStripButton.Enabled = false;
627
            else if (currentTab.history.pointerCur > 0 || currentTab.history.pointerCur < currentTab.history.pointerEnd)
628
                Forward_toolStripButton.Enabled = true;
629
        }
630

631
        private void Caret_PositionChanged(object sender, EventArgs e)
632
        {
633
            string ext = Path.GetExtension(currentTab.filename).ToLowerInvariant();
634
            if (ext != ".ssl" && ext != ".h") return;
635

636
            TextLocation _position = currentActiveTextAreaCtrl.Caret.Position;
637
            int curLine = _position.Line + 1;
638
            LineStripStatusLabel.Text = "Line: " + curLine;
639
            ColStripStatusLabel.Text = "Col: " + (_position.Column + 1);
640

641
            Utilities.SelectedTextColorRegion(_position, currentActiveTextAreaCtrl);
642

643
            if (updateHighlightPocedure) HighlightCurrentPocedure(_position.Line);
644

645
            if (PosChangeType == PositionType.Disabled) return;
646
        PosChange:
647
            if (PosChangeType >= PositionType.NoStore) { // also OverridePos
648
                if (PosChangeType == PositionType.OverridePos && currentTab.history.pointerCur != -1)
649
                    currentTab.history.linePosition[currentTab.history.pointerCur] = _position;
650

651
                PosChangeType = PositionType.AddPos; // set default
652
                return;
653
            }
654

655
            int diff = Math.Abs(curLine - currentTab.history.prevPosition);
656
            currentTab.history.prevPosition = curLine;
657
            if (diff > 1) {
658
                currentTab.history.pointerCur++;
659
                if (currentTab.history.pointerCur >= currentTab.history.linePosition.Count)
660
                    currentTab.history.linePosition.Add(_position);
661
                else
662
                    currentTab.history.linePosition[currentTab.history.pointerCur] = _position;
663
                currentTab.history.pointerEnd = currentTab.history.pointerCur;
664
            } else {
665
                PosChangeType = PositionType.OverridePos;
666
                goto PosChange;
667
            }
668

669
            SetBackForwardButtonState();
670
        }
671

672
        private void Back_toolStripButton_Click(object sender, EventArgs e)
673
        {
674
            if (currentTab == null || currentTab.history.pointerCur == 0)
675
                return;
676

677
            currentTab.history.pointerCur--;
678
            GotoViewLine();
679
        }
680

681
        private void Forward_toolStripButton_Click(object sender, EventArgs e)
682
        {
683
            if (currentTab == null || currentTab.history.pointerCur >= currentTab.history.pointerEnd)
684
                return;
685

686
            currentTab.history.pointerCur++;
687
            GotoViewLine();
688
        }
689

690
        private void GotoViewLine()
691
        {
692
            PosChangeType = PositionType.NoStore;
693
            TextLocation _position = currentTab.history.linePosition[currentTab.history.pointerCur];
694
            currentActiveTextAreaCtrl.Caret.Position = _position;
695
            currentTab.history.prevPosition = _position.Line + 1;
696

697
            int firstLine = currentActiveTextAreaCtrl.TextArea.TextView.FirstVisibleLine;
698
            int lastLine = firstLine + currentActiveTextAreaCtrl.TextArea.TextView.VisibleLineCount - 1;
699
            if (_position.Line <= firstLine || _position.Line + 1 >= lastLine)
700
                currentActiveTextAreaCtrl.CenterViewOn(currentActiveTextAreaCtrl.Caret.Line, 0);
701

702
            SetBackForwardButtonState();
703
        }
704
        #endregion
705

706
        #region Procedure function Create/Rename/Delete/Move
707
        // Create Handlers Procedures
708
        public void CreateProcBlock(string name)
709
        {
710
            if (currentTab.parseInfo.CheckExistsName(name, false)) {
711
                MessageBox.Show("A procedure with this name has already been declared.", "Info");
712
                return;
713
            }
714
            byte line = (name == "look_at_p_proc" || name == "description_p_proc") ? (byte)1 : (byte)0;
715

716
            ProcForm CreateProcFrm = new ProcForm(name, true);
717

718
            if (ProcTree.SelectedNode != null && ProcTree.SelectedNode.Tag is Procedure)
719
                CreateProcFrm.CopyProcedure = false;
720
            else
721
                CreateProcFrm.groupBoxProcedure.Enabled = false;
722

723
            ProcTree.HideSelection = false;
724

725
            if (CreateProcFrm.ShowDialog() == DialogResult.Cancel) {
726
                ProcTree.HideSelection = true;
727
                return;
728
            }
729

730
            InsertAt placeAt = CreateProcFrm.PlaceAt;
731

732
            ProcedureBlock block = new ProcedureBlock();
733
            if (placeAt == InsertAt.After) {
734
                var proc = currentHighlightProc ?? (Procedure)ProcTree.SelectedNode.Tag;
735
                if (proc != null) {
736
                    block.begin  = proc.d.start;
737
                    block.end    = proc.d.end;
738
                    block.declar = proc.d.declared;
739
                } else {
740
                    placeAt = InsertAt.Caret;
741
                }
742
            }
743
            PrepareInsertProcedure(CreateProcFrm.ProcedureName, block, placeAt, line);
744

745
            CreateProcFrm.Dispose();
746
            ProcTree.HideSelection = true;
747
        }
748

749
        // Create Procedures
750
        private void createProcedureToolStripMenuItem_Click(object sender, EventArgs e)
751
        {
752
            if (currentTab == null || !currentTab.shouldParse) return;
753

754
            string word = null;
755

756
            bool IsSelectProcedure = ProcTree.SelectedNode != null && ProcTree.SelectedNode.Tag is Procedure;
757
            if (IsSelectProcedure)
758
                word = ProcTree.SelectedNode.Name;
759
            else if (currentActiveTextAreaCtrl.SelectionManager.HasSomethingSelected)
760
                word = currentActiveTextAreaCtrl.SelectionManager.SelectedText;
761

762
            ProcForm CreateProcFrm = new ProcForm(word, false, true);
763

764
            CreateProcFrm.SetInsertAtArter = true;
765
            if (!IsSelectProcedure && currentHighlightProc == null) {
766
                CreateProcFrm.groupBoxProcedure.Enabled = false;
767
            }
768

769
            ProcTree.HideSelection = false;
770
            if (CreateProcFrm.ShowDialog() == DialogResult.Cancel) {
771
                ProcTree.HideSelection = true;
772
                return;
773
            }
774

775
            string name = CreateProcFrm.CheckName;
776
            if (name == null) return;
777
            if (currentTab.parseInfo.CheckExistsName(name, NameType.Proc)) {
778
                MessageBox.Show("A procedure with this name has already been declared.", "Info");
779
                return;
780
            }
781

782
            InsertAt placeAt = CreateProcFrm.PlaceAt;
783

784
            ProcedureBlock block = new ProcedureBlock();
785
            if (CreateProcFrm.CopyProcedure || placeAt == InsertAt.After) {
786
                Procedure proc = currentHighlightProc;
787
                if (ProcTree.SelectedNode != null) {
788
                    proc = ProcTree.SelectedNode.Tag  as Procedure;
789
                    if (proc == null) proc = currentHighlightProc;
790
                }
791
                if (proc != null) {
792
                    block.begin  = proc.d.start;
793
                    block.end    = proc.d.end;
794
                    block.declar = proc.d.declared;
795
                    block.copy   = CreateProcFrm.CopyProcedure;
796
                } else {
797
                    placeAt = InsertAt.Caret;
798
                }
799
            }
800

801
            name = CreateProcFrm.ProcedureName;
802
            PrepareInsertProcedure(name, block, placeAt);
803

804
            CreateProcFrm.Dispose();
805
            ProcTree.HideSelection = true;
806
        }
807

808
        // Create procedure block
809
        private void PrepareInsertProcedure(string name, ProcedureBlock block, InsertAt placeAt = InsertAt.Caret, byte overrides = 0)
810
        {
811
            int declrLine, procLine = 0, caretline = 3;
812
            string procbody;
813

814
            //Copy from procedure
815
            if (block.copy) {
816
                procbody = Utilities.GetRegionText(currentDocument, block.begin, block.end - 2) + Environment.NewLine;
817
                overrides = 1;
818
            } else
819
                procbody = new string(' ', Settings.tabSize) + ("script_overrides;\r\n\r\n");
820

821
            string procblock = (overrides > 0)
822
                       ? "\r\nprocedure " + name + " begin\r\n" + procbody + "end"
823
                       : "\r\nprocedure " + name + " begin\r\n\r\nend";
824

825
            int total = currentDocument.TotalNumberOfLines - 1;
826
            Procedure pTop = currentTab.parseInfo.GetTopProcedure();
827
            int declrEndLine = ParserInternal.GetRegionDeclaration(currentTab.textEditor.Document.TextContent, (pTop != null) ? pTop.d.start - 1 : total).end;
828
            int caretLine = currentActiveTextAreaCtrl.Caret.Line;
829

830
            if (total == 0 || caretLine <= declrEndLine) placeAt = InsertAt.End;
831

832
            // declaration line
833
            if (placeAt == InsertAt.Caret) {
834
                procLine = caretLine;
835
                Procedure p = currentTab.parseInfo.GetNearProcedure(procLine); // найти процедуру которая расположена рядом
836
                if (p != null) {
837
                    declrLine = p.d.Declaration;
838
                    if (procLine < p.d.start) {
839
                        declrLine--; // размесить над
840
                    }
841
                    if ((procLine + 2) == p.d.start) {
842
                        procblock += Environment.NewLine;
843
                    }
844
                } else {
845
                    placeAt = InsertAt.End;
846
                    ParserInternal.UpdateParseBuffer(currentTab.textEditor.Text);
847
                    declrLine = ParserInternal.GetEndLineProcDeclaration();
848
                }
849
            }
850
            else if (placeAt == InsertAt.After)
851
                declrLine = block.declar;
852
            else {
853
                ParserInternal.UpdateParseBuffer(currentTab.textEditor.Text);
854
                declrLine = ParserInternal.GetEndLineProcDeclaration();
855
            }
856
            // procedure line
857
            if (placeAt == InsertAt.After) {
858
                procLine = block.end; // after current procedure
859
                if (procLine > total)
860
                    procLine = block.end = total;
861
                else if (block.end < total)
862
                    block.end++;
863

864
                if (block.end == total || TextUtilities.GetLineAsString(currentDocument, block.end).Trim().Length > 0)
865
                    procblock += Environment.NewLine;
866
            }
867
            else if (placeAt == InsertAt.End) {
868
                procLine = total; // paste to end script
869
            }
870
            if (declrLine <= -1) declrLine = declrEndLine  + 1;
871

872
            Utilities.InsertProcedure(currentActiveTextAreaCtrl, name, procblock, declrLine, procLine, ref caretline);
873

874
            caretline += procLine + overrides;
875
            currentActiveTextAreaCtrl.Caret.Column = 0;
876
            currentActiveTextAreaCtrl.Caret.Line = caretline;
877
            currentActiveTextAreaCtrl.CenterViewOn(caretline, 0);
878

879
            currentHighlightProc = null;
880
            HighlightProcedures.AddToList(currentDocument, name);
881
            ForceParseScript();
882
            SetFocusDocument();
883
        }
884

885
        // Rename Procedures
886
        private void renameProcedureToolStripMenuItem_Click(object sender, EventArgs e)
887
        {
888
            Procedure proc = ProcTree.SelectedNode.Tag as Procedure;
889
            if (proc == null) return;
890

891
            ProcTree.HideSelection = false;
892
            string newName = Refactor.RenameProcedure(proc, currentDocument, currentTab, tabs);
893
            ProcTree.HideSelection = true;
894

895
            if (newName != null) {
896
                ProcTree.SelectedNode.Text = newName; // обновить имя в обозревателе
897

898
                // выполнить обновление
899
                ProcTree.Tag = TreeStatus.freeze; // предотвращает следующее обновление обозревателя
900
                ForceParseScript();
901
                SetFocusDocument();
902
            }
903
        }
904

905
        // Delete Procedures
906
        private void deleteProcedureToolStripMenuItem_Click(object sender, EventArgs e)
907
        {
908
            Procedure proc = ProcTree.SelectedNode.Tag as Procedure;
909
            if (proc == null) return;
910

911
            //if (proc.IsImported) {
912
            //    MessageBox.Show("You can't delete the imported procedure.");
913
            //    return;
914
            //}
915

916
            if (MessageBox.Show("Are you sure you want to delete \"" + proc.name + "\" procedure?",
917
                                "Warning", MessageBoxButtons.YesNo) == DialogResult.No) {
918
                return;
919
            }
920
            Utilities.PrepareDeleteProcedure(proc, currentDocument);
921
            ProcTree.Nodes.Remove(ProcTree.SelectedNode);
922

923
            currentActiveTextAreaCtrl.SelectionManager.ClearSelection();
924

925
            HighlightProcedures.DeleteFromList(currentDocument, proc.name);
926

927
            ProcTree.Tag = TreeStatus.freeze; // предотвращает следующее обновление обозревателя
928
            ForceParseScript();
929
            UpdateNodesTags();
930
            SetFocusDocument();
931
            HighlightCurrentPocedure(currentActiveTextAreaCtrl.Caret.Line);
932
        }
933

934
        private void MoveProcedure(int sIndex)
935
        {
936
            bool moveToEnd = false;
937
            int root = ProcTree.Nodes.Count - 1;
938

939
            if (sIndex > moveActive) {
940
                if (sIndex >= (ProcTree.Nodes[root].Nodes.Count - 1))
941
                    moveToEnd = true;
942
                else
943
                    sIndex++;
944
            } else if (sIndex == moveActive)
945
                return; //exit move
946

947
            Procedure moveProc = (Procedure)ProcTree.Nodes[root].Nodes[moveActive].Tag;
948
            // copy body
949
            ParserInternal.UpdateParseBuffer(currentDocument.TextContent);
950
            ProcedureBlock block = ParserInternal.GetProcedureBlock(moveProc.name, 0, true);
951
            block.declar = moveProc.d.declared;
952

953
            string copy_defproc;
954
            string copy_procbody = Environment.NewLine + Utilities.GetRegionText(currentDocument, block.begin, block.end);
955

956
            currentDocument.UndoStack.StartUndoGroup();
957
            currentActiveTextAreaCtrl.SelectionManager.ClearSelection();
958

959
            Utilities.DeleteProcedure(currentDocument, block, out copy_defproc);
960

961
            string name = ((Procedure)ProcTree.Nodes[root].Nodes[sIndex].Tag).Name;
962

963
            ParserInternal.UpdateParseBuffer(currentDocument.TextContent);
964
            // insert declration
965
            int offset = 0;
966
            if (copy_defproc != null) {
967
                int p_def = ParserInternal.GetDeclarationProcedureLine(name);
968
                if (moveToEnd) p_def++;
969
                if (p_def != -1) offset = currentDocument.PositionToOffset(new TextLocation(0, p_def));
970
                currentDocument.Insert(offset, copy_defproc + Environment.NewLine);
971
            }
972
            //paste proc block
973
            block = ParserInternal.GetProcedureBlock(name, 0, true);
974
            int p_begin;
975
            if (moveToEnd) {
976
                p_begin = block.end + 1;
977
                copy_procbody = Environment.NewLine + copy_procbody;
978
            } else {
979
                p_begin = block.begin;
980
                copy_procbody += Environment.NewLine;
981
            }
982
            offset = currentDocument.PositionToOffset(new TextLocation(0, p_begin));
983
            offset += TextUtilities.GetLineAsString(currentDocument, p_begin).Length;
984

985
            currentDocument.Insert(offset, copy_procbody);
986
            currentDocument.UndoStack.EndUndoGroup();
987

988
            // Перемещение процедуры в дереве
989
            if (sIndex > moveActive && !moveToEnd)
990
                sIndex--;
991

992
            TreeNode nd = ProcTree.Nodes[root].Nodes[moveActive];
993
            ProcTree.Nodes[root].Nodes.RemoveAt(moveActive);
994
            ProcTree.Nodes[root].Nodes.Insert(sIndex, nd);
995
            ProcTree.SelectedNode = ProcTree.Nodes[root].Nodes[sIndex];
996
            ProcTree.Focus();
997
            ProcTree.Select();
998

999
            currentHighlightProc = null;
1000
            ParserInternal.UpdateProcInfo(ref currentTab.parseInfo, currentDocument.TextContent, currentTab.filepath);
1001
            CodeFolder.UpdateFolding(currentDocument, currentTab.filename, currentTab.parseInfo.procs);
1002
        }
1003

1004
        private void moveProcedureToolStripMenuItem_Click(object sender, EventArgs e)
1005
        {
1006
            if (ProcTree.SelectedNode == null)
1007
                return;
1008
            if (moveActive == -1) {
1009
                moveActive = ProcTree.SelectedNode.Index;
1010
                ProcTree.SelectedNode.ForeColor = Color.Red;
1011
                ProcTree.AfterSelect -= TreeView_AfterSelect;
1012
                ProcTree.SelectedNode = ProcTree.Nodes[0];
1013
                ProcTree.AfterSelect += ProcTree_AfterSelect;
1014
                //ProcTree.ShowNodeToolTips = false;
1015
            }
1016
        }
1017

1018
        private void ProcTree_MouseMove(object sender, MouseEventArgs e)
1019
        {
1020
            if (moveActive < 0)
1021
                return;
1022

1023
            TreeNode node = ProcTree.GetNodeAt(e.Location);
1024
            if (node != null && Functions.NodeHitCheck(e.Location, node.Bounds)) {
1025
                if (node.Index > moveActive)
1026
                    ProcTree.Cursor = Cursors.PanSouth;
1027
                else
1028
                    ProcTree.Cursor = Cursors.PanNorth;
1029
            } else
1030
                ProcTree.Cursor = Cursors.No;
1031
        }
1032

1033
        private void ProcTree_AfterSelect(object sender, TreeViewEventArgs e)
1034
        {
1035
            if (e.Node.Parent == null || e.Node.Parent.Text != TREEPROCEDURES[1])
1036
                return;
1037
            ProcTree.AfterSelect -= ProcTree_AfterSelect;
1038
            currentTab.textEditor.TextChanged -= textChanged;
1039
            MoveProcedure(e.Node.Index);
1040
            currentTab.textEditor.TextChanged += textChanged;
1041
            ProcTree.AfterSelect += TreeView_AfterSelect;
1042
            ProcTree.SelectedNode.ForeColor = ProcTree.ForeColor;
1043
            ProcTree.Cursor = Cursors.Hand;
1044
            moveActive = -1;
1045
            //ProcTree.ShowNodeToolTips = true;
1046
            // set changed document
1047
            textChanged(null, EventArgs.Empty);
1048
        }
1049

1050
        private void ProcTree_MouseLeave(object sender, EventArgs e)
1051
        {
1052
            if (moveActive != -1) {
1053
                ProcTree.AfterSelect -= ProcTree_AfterSelect;
1054
                ProcTree.AfterSelect += TreeView_AfterSelect;
1055
                ProcTree.Nodes[ProcTree.Nodes.Count - 1].Nodes[moveActive].ForeColor = ProcTree.ForeColor;
1056
                ProcTree.Cursor = Cursors.Hand;
1057
                moveActive = -1;
1058
            }
1059
        }
1060

1061
        private void ProcTree_MouseClick(object sender, MouseEventArgs e)
1062
        {
1063
            if (e.Button == MouseButtons.Right) {
1064
                ProcTree_MouseLeave(null, null);
1065
            }
1066
        }
1067

1068
        private void ProcMnContext_Opening(object sender, System.ComponentModel.CancelEventArgs e)
1069
        {
1070
            if (ProcTree.SelectedNode != null && ProcTree.SelectedNode.Tag is Procedure &&
1071
                ProcTree.SelectedNode.Parent != null && (int)ProcTree.SelectedNode.Parent.Tag == 1)
1072
            {
1073
                Procedure proc = ProcTree.SelectedNode.Tag as Procedure;
1074
                string pName = proc.Name;
1075
                if (pName.IndexOf("node") > -1 || pName == "talk_p_proc")
1076
                    editNodeCodeToolStripMenuItem.Enabled = true;
1077
                else
1078
                    editNodeCodeToolStripMenuItem.Enabled = false;
1079
                renameProcedureToolStripMenuItem.Enabled = true;
1080
                moveProcedureToolStripMenuItem.Enabled = true;
1081
                deleteProcedureToolStripMenuItem.Enabled = true;
1082
                deleteProcedureToolStripMenuItem.Text = "Delete: " + proc.name;
1083
            } else {
1084
                editNodeCodeToolStripMenuItem.Enabled = false;
1085
                renameProcedureToolStripMenuItem.Enabled = false;
1086
                moveProcedureToolStripMenuItem.Enabled = false;
1087
                deleteProcedureToolStripMenuItem.Enabled = false;
1088
                deleteProcedureToolStripMenuItem.Text = "Delete procedure";
1089
            }
1090
        }
1091
        #endregion
1092
    }
1093
}
1094

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.