Sfall-ScriptEditor

Форк
0
372 строки · 17.0 Кб
1
using System;
2
using System.Collections.Generic;
3
using System.IO;
4
using System.Linq;
5
using System.Text;
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

15
namespace ScriptEditor.TextEditorUtilities
16
{
17
    internal sealed class Refactor
18
    {
19
        internal static void Rename(IParserInfo item, IDocument document, TabInfo cTab, List<TabInfo> tabs)
20
        {
21
            string newName;
22
            switch ((NameType)item.Type())
23
            {
24
                case NameType.LVar: // local procedure variable
25
                    Variable lvar = (Variable)item;
26
                    newName = lvar.name;
27
                    if (!ProcForm.CreateRenameForm(ref newName, "Local Variable") || newName == lvar.name)
28
                        return;
29
                    if (cTab.parseInfo.CheckExistsName(newName, NameType.LVar, lvar.fdeclared, lvar.d.declared)) {
30
                        MessageBox.Show("The local variable this name already exists.", "Unable to rename");
31
                        return;
32
                    }
33
                    RenameVariable(lvar, newName, RegexOptions.IgnoreCase, document); // rename only via references
34
                    break;
35

36
                case NameType.GVar: // script variable
37
                    Variable gvar = (Variable)item;
38
                    newName = gvar.name;
39
                    if (!ProcForm.CreateRenameForm(ref newName, "Script Variable") || newName == gvar.name)
40
                        return;
41
                    if (cTab.parseInfo.CheckExistsName(newName, NameType.GVar)) {
42
                        MessageBox.Show("The variable/procedure or declared macro this name already exists.", "Unable to rename");
43
                        return;
44
                    }
45
                    RenameVariable(gvar, newName, RegexOptions.IgnoreCase, document); // rename only via references
46
                    break;
47

48
                case NameType.Proc:
49
                    RenameProcedure((Procedure)item, document, cTab, tabs);
50
                    return;
51

52
                case NameType.Macro:
53
                    Macro macros = (Macro)item;
54

55
                    bool isGlobal = ProgramInfo.macrosGlobal.ContainsKey(macros.token);
56
                    newName = macros.token;
57

58
                    if (!ProcForm.CreateRenameForm(ref newName, (isGlobal) ? "Global Macro" : "Local Macro") || newName == macros.token)
59
                        return;
60

61
                    if (cTab.parseInfo.CheckExistsName(newName, NameType.Macro)) {
62
                        MessageBox.Show("The variable/procedure or declared macro this name already exists.", "Unable to rename");
63
                        return;
64
                    }
65
                    int diff = newName.Length - macros.token.Length;
66

67
                    // Для глобальных требуется переименовать все макросы во всех открытых вкладках и во всех файлах проекта/мода
68
                    if (isGlobal) {
69
                        RenameGlobalMacros(macros, newName, cTab, tabs, diff);
70
                        // обновить макросы
71
                        GetMacros.GetGlobalMacros(Settings.pathHeadersFiles);
72
                        return;
73
                    }
74
                    RenameMacros(macros.token, newName, RegexOptions.None, document);
75
                    if (diff != 0) DefineMacroAdjustSpaces(macros, document, diff);
76
                    break;
77
            }
78
        }
79

80
        #region Переименование макросов
81

82
        private static void RenameMacros(string find, string newName, RegexOptions option, IDocument document)
83
        {
84
            document.UndoStack.StartUndoGroup();
85

86
            int offset = 0;
87
            while (offset < document.TextLength)
88
            {
89
                offset = Utilities.SearchWholeWord(document.TextContent, find, offset, option);
90
                if (offset == -1)
91
                    break;
92
                document.Replace(offset, find.Length, newName);
93
                offset += newName.Length;
94
            }
95
            document.UndoStack.EndUndoGroup();
96
        }
97

98
        public struct PreviewMatch
99
        {
100
            public string previewText;
101
            public Match  match;
102
            public TabInfo tab;
103

104
            public PreviewMatch(string previewText, Match match, TabInfo tab = null)
105
            {
106
                this.previewText = previewText;
107
                this.match = match;
108
                this.tab = tab;
109
            }
110

111
            public PreviewMatch(PreviewMatch obj)
112
            {
113
                this.previewText = obj.previewText;
114
                this.match = obj.match;
115
                this.tab = obj.tab;
116
            }
117
        }
118

119
        private static void MatchesCollect(ref Dictionary<string, List<PreviewMatch>> preview, Regex regex, string filename, string textContent, TabInfo tab = null)
120
        {
121
            MatchCollection matches = regex.Matches(textContent);
122

123
            if (matches.Count > 0) {
124
                List<PreviewMatch> list = new List<PreviewMatch>();
125
                foreach (Match match in matches)
126
                {
127
                    int pEnd = 0;
128
                    for (int i = match.Index + match.Length; i < textContent.Length; i++)
129
                    {
130
                        if (textContent[i] == '\n') {
131
                            pEnd = i;
132
                            break;
133
                        }
134
                    }
135
                    string previewText = textContent.Substring(match.Index, pEnd - match.Index).TrimEnd();
136
                    list.Add(new PreviewMatch(previewText, match, tab));
137
                }
138
                preview.Add(filename ?? tab.filepath, list);
139
            }
140
        }
141

142
        private static Dictionary<string, List<PreviewMatch>> PreviewRenameGlobalMacros(Regex regex, List<TabInfo> tabs)
143
        {
144
            Dictionary<string, List<PreviewMatch>> preview = new Dictionary<string, List<PreviewMatch>>(); // file => mathes
145

146
            foreach (var tab in tabs)
147
            {
148
                string textContent = tab.textEditor.Document.TextContent;
149
                MatchesCollect(ref preview, regex, null, textContent, tab);
150
            }
151
            return preview;
152
        }
153

154
        private static Dictionary<string, List<PreviewMatch>> PreviewRenameGlobalMacros(Regex regex, List<TabInfo> tabs, List<string> files)
155
        {
156
            ProgressBarForm pf = (files.Count > 100) ? new ProgressBarForm(Form.ActiveForm, files.Count, "Идет поиск совпадений в файлах проекта...") : null;
157
            Dictionary<string, List<PreviewMatch>> preview = new Dictionary<string, List<PreviewMatch>>(); // file => mathes
158

159
            foreach (var file in files)
160
            {
161
                if (pf != null) pf.IncProgress();
162
                if (TextEditor.CheckTabs(file, tabs)) continue; // next file
163

164
                string textContent = System.IO.File.ReadAllText(file);
165
                MatchesCollect(ref preview, regex, file, textContent);
166
            }
167
            if (pf != null) pf.Dispose();
168
            return preview;
169
        }
170

171
        private static void RenameGlobalMacros(Macro macros, string newName, TabInfo cTab, List<TabInfo> tabs, int diff)
172
        {
173
            Regex s_regex = new Regex(@"\b" + macros.token + @"\b", RegexOptions.None);
174

175
            // preview renamed macros open scripts
176
            Dictionary<string, List<PreviewMatch>> matchTabs = PreviewRenameGlobalMacros(s_regex, tabs);  // file => mathes
177

178
            List<string> files = Directory.GetFiles(Settings.solutionProjectFolder, "*.ssl", SearchOption.AllDirectories).ToList();
179
            files.AddRange(Directory.GetFiles(Settings.solutionProjectFolder, "*.h", SearchOption.AllDirectories).ToList());
180

181
            // preview renamed macros open scripts
182
            Dictionary<string, List<PreviewMatch>> matchFiles = PreviewRenameGlobalMacros(s_regex, tabs, files);
183

184
            // выбор совпадений
185
            var previewForm = new PreviewRename(macros.defname, macros.defname.Replace(macros.token, newName));
186
            previewForm.BuildTreeMatches(matchTabs, matchFiles);
187

188
            matchTabs.Clear();
189
            matchFiles.Clear();
190

191
            if (previewForm.ShowDialog() != DialogResult.OK) return;
192

193
            previewForm.GetSelectedMatches(ref matchTabs, ref matchFiles);
194
            previewForm.Dispose();
195

196
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
197

198
            int isAdjustSpaces = diff;
199
            cTab.DisableParseAndStatusChange = true;
200

201
            int replaceLen = macros.token.Length;
202

203
            foreach (var tabMatches in matchTabs)
204
            {
205
                TabInfo tab = null;
206
                int replace_count = 0;
207
                foreach (var matches in tabMatches.Value)
208
                {
209
                    tab = matches.tab;
210
                    Match match = matches.match;
211
                    int offset = (diff * replace_count) + match.Index;
212
                    tab.textEditor.Document.Replace(offset, replaceLen, newName);
213
                    replace_count++;
214
                }
215
                if (tab != null) {
216
                    var document = tab.textEditor.Document;
217
                    if (isAdjustSpaces != 0 && string.Equals(tab.filepath, macros.fdeclared, StringComparison.OrdinalIgnoreCase)) {
218
                        DefineMacroAdjustSpaces(macros, document, diff);
219
                        isAdjustSpaces = 0;
220
                    }
221
                    document.UndoStack.ClearAll();
222
                    tab.SaveInternal(document.TextContent, tab.textEditor.Encoding); // сохранить изменения в файл
223
                }
224
            }
225

226
            if (matchFiles.Count == 0) {
227
                cTab.DisableParseAndStatusChange = false;
228
                return;
229
            }
230
            // замена в файлах проекта
231
            ProgressBarForm pf = (matchFiles.Count > 100) ? new ProgressBarForm(Form.ActiveForm, matchFiles.Count, "Идет замена в файлах проекта...") : null;
232

233
            int total = 0;
234
            foreach (var fileMatches in matchFiles)
235
            {
236
                string textContent = System.IO.File.ReadAllText(fileMatches.Key);
237
                total += fileMatches.Value.Count;
238

239
                int replace_count = 0;
240
                foreach (var matches in fileMatches.Value)
241
                {
242
                    int offset = (diff * replace_count) + matches.match.Index;
243
                    textContent = textContent.Remove(offset, matches.match.Length);
244
                    textContent = textContent.Insert(offset, newName);
245
                    replace_count++;
246
                }
247
                if (isAdjustSpaces != 0 && string.Equals(fileMatches.Key, macros.fdeclared, StringComparison.OrdinalIgnoreCase)) {
248
                    DefineMacroAdjustSpaces(macros, newName, ref textContent, diff);
249
                    isAdjustSpaces = 0;
250
                }
251
                if (replace_count > 0) {
252
                    File.WriteAllText(fileMatches.Key, textContent, (Settings.saveScriptUTF8) ? new UTF8Encoding(false) : Encoding.Default);
253
                }
254
                if (pf != null) pf.IncProgress();
255
            }
256
            if (pf != null) pf.Dispose();
257

258
            //MessageBox.Show(String.Format("Произведено переименование {0} макросов, в {1} файлах.", total, previewFiles.Count));
259
             cTab.DisableParseAndStatusChange = false;
260
        }
261

262
        // insert/delete spaces in define macro
263
        private static void DefineMacroAdjustSpaces(Macro macros, string newName, ref string textContent, int diff)
264
        {
265
            int offset = 0;
266
            while (true)
267
            {
268
                offset = textContent.IndexOf(" " + newName, offset); // ищем первое определение
269
                if (offset == -1 || offset >= textContent.Length) return;
270

271
                char c = textContent[offset + newName.Length + 1];
272
                if (c != '(' && !char.IsWhiteSpace(c)) continue; // перейти к следующему поиску если имя определения макроса не заканчивается символами пробела или открыващей скобкой
273

274
                if (textContent.IndexOf("#define", offset - 7, 7) != -1) break; // да, это строка определения макроса
275
            }
276
            offset += (macros.defname.Length + diff) + 1;
277

278
            if (diff > 0) {
279
                int removeCount = 0;
280
                for (int i = 0; i < diff; i++)
281
                {
282
                    if (!Char.IsWhiteSpace(textContent[offset + i + 1])) break;
283
                    removeCount++;
284
                }
285
                if (removeCount > 0) textContent = textContent.Remove(offset, removeCount);
286
            } else
287
                textContent = textContent.Insert(offset, new string(' ', Math.Abs(diff)));
288
        }
289

290
        // insert/delete spaces in define macro
291
        private static void DefineMacroAdjustSpaces(Macro macros, IDocument document, int diff)
292
        {
293
            int offset = document.PositionToOffset(new TextLocation(0, macros.declared - 1));
294
            offset += (macros.defname.Length + 8) + diff;
295

296
            if (diff > 0) {
297
                int removeCount = 0;
298
                for (int i = 0; i < diff; i++)
299
                {
300
                    if (!Char.IsWhiteSpace(document.GetCharAt(offset + i + 1))) break;
301
                    removeCount++;
302
                }
303
                if (removeCount > 0) document.Remove(offset, removeCount);
304
            } else
305
                document.Insert(offset, new string(' ',  Math.Abs(diff)));
306
        }
307
        #endregion
308

309
        private static void RenameVariable(Variable var, string newName, RegexOptions option, IDocument document)
310
        {
311
            Utilities.ReplaceByReferences(new Regex(@"\b" + var.name + @"\b", option), document, var, newName, newName.Length - var.name.Length);
312
        }
313

314
        // вызывается из редактора нодов диалога
315
        internal static string RenameProcedure(string name, IDocument document, TabInfo cTab)
316
        {
317
            Procedure proc = cTab.parseInfo.GetProcedureByName(name);
318
            return (proc != null) ? RenameProcedure(proc, document, cTab) : null;
319
        }
320

321
        // Search and replace procedure name in script text
322
        internal static string RenameProcedure(Procedure proc, IDocument document, TabInfo cTab, List<TabInfo> tabs = null)
323
        {
324
            string newName = proc.name;
325
            // form ini
326
            if (!ProcForm.CreateRenameForm(ref newName, "Procedure") || newName == proc.name)
327
                return null;
328

329
            if (cTab.parseInfo.CheckExistsName(newName, NameType.Proc)) {
330
                MessageBox.Show("The procedure/variable or declared macro with this name already exists.", "Unable to rename");
331
                return null;
332
            }
333

334
            bool extFile = false;
335
            if (tabs != null && proc.filename != cTab.filename.ToLowerInvariant()) { // не совсем понятно, при каких условиях это верно
336
                switch (MessageBox.Show("Also renaming the procedure in a file: " + proc.filename.ToUpper() + " ?", "Procedure rename", MessageBoxButtons.YesNoCancel)) {
337
                    case DialogResult.Cancel :
338
                        return null;
339
                    case DialogResult.Yes :
340
                        extFile = true;
341
                        break;
342
                }
343
            }
344
            int differ = newName.Length - proc.name.Length;
345

346
            Regex s_regex;
347
            if (proc.References().Length == 0) {
348
                s_regex = new Regex(@"(\bprocedure\s|\bcall\s|[=,(]\s*)\s*" + proc.Name + @"\b", // осуществить поиск всех процедур совпадающих по имени
349
                                    RegexOptions.Multiline | RegexOptions.IgnoreCase);
350
                Utilities.ReplaceIDocumentText(s_regex, document, newName, differ);
351
            } else {
352
                s_regex = new Regex(@"\b" + proc.Name + @"\b", RegexOptions.Multiline | RegexOptions.IgnoreCase);
353
                Utilities.ReplaceByReferences(s_regex, document, proc, newName, differ); // rename by reference
354
            }
355

356
            // rename in other file/tab
357
            if (extFile) {
358
                string text = File.ReadAllText(proc.fstart);
359
                Utilities.ReplaceSpecialText(s_regex, ref text, newName, differ);
360
                File.WriteAllText(proc.fstart, text);
361

362
                TabInfo tab = TextEditor.CheckTabs(tabs, proc.fstart);
363
                if (tab != null) {
364
                    Utilities.ReplaceIDocumentText(s_regex, tab.textEditor.Document, newName, differ);
365
                    tab.FileTime = File.GetLastWriteTime(proc.fstart);
366
                }
367
            }
368
            TextEditor.currentHighlightProc = null;
369
            return newName;
370
        }
371
    }
372
}
373

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

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

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

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