|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
1 |
using System.Text.RegularExpressions; |
| |
2 |
using Microsoft.VisualStudio.TextManager.Interop; |
| |
3 |
|
| |
4 |
namespace BooLangService |
| |
5 |
{ |
| |
6 |
/// <summary> |
| |
7 |
/// Checks the current users line and indents or dedents the next one. |
| |
8 |
/// </summary> |
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
9 |
public class LineIndenter : ILineIndenter |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
10 |
{ |
| |
11 |
// matches comments on the end of a line |
| |
12 |
private readonly Regex removeCommentsRegExp = new Regex(@".*((?:#|\/\/|\/\*).*)$", RegexOptions.Compiled); |
| |
13 |
// matches a dedenting code line (pass, return, return xxx, return if x = x, return xxx unless x = x, etc...) |
| |
14 |
private readonly Regex dedentRegExp = new Regex(@"(?:return|pass)(?:[\t ]?[\w]*[\t ]?(?<exp>(?:if|unless)))?", RegexOptions.Compiled); |
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
15 |
private readonly ISource source; |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
16 |
private readonly IVsTextView view; |
| |
17 |
private readonly char IndentChar; |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
18 |
|
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
19 |
public LineIndenter(ISource source, IVsTextView view) |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
20 |
{ |
| |
21 |
this.source = source; |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
22 |
this.view = view; |
| |
23 |
|
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
24 |
IndentChar = source.UseTabs ? '\t' : ' '; |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
25 |
} |
| |
26 |
|
| |
27 |
/// <summary> |
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
28 |
/// Sets the indentation for the next lineNumber. |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
29 |
/// </summary> |
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
30 |
public void SetIndentationForNextLine(int lineNumber) |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
31 |
{ |
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
32 |
string previousLine = GetPreviousNonWhitespaceLine(lineNumber); |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
33 |
int indentLevel = GetIndentLevel(previousLine); |
| |
34 |
|
| |
35 |
if (RequiresIndent(previousLine)) |
| |
36 |
indentLevel++; |
| |
37 |
else if (RequiresDedent(previousLine) && indentLevel > 0) |
| |
38 |
indentLevel--; |
| |
39 |
|
| |
40 |
var nextLine = "".PadRight(indentLevel, IndentChar); |
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
41 |
var firstChar = source.ScanToNonWhitespaceChar(lineNumber); |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
42 |
|
|
44392911
»
|
jagregory |
2008-10-14 |
Added indentation tests and... |
43 |
source.SetText(lineNumber, firstChar, nextLine); |
| |
44 |
view.PositionCaretForEditing(lineNumber, indentLevel); |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
45 |
} |
| |
46 |
|
| |
47 |
private int GetIndentLevel(string line) |
| |
48 |
{ |
| |
49 |
var count = 0; |
| |
50 |
|
| |
51 |
foreach (var c in line) |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
52 |
{ |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
53 |
if (c != IndentChar) |
| |
54 |
break; // got to the text on the line |
| |
55 |
|
| |
56 |
count++; |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
57 |
} |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
58 |
|
| |
59 |
return count; |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
60 |
} |
| |
61 |
|
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
62 |
private string GetPreviousNonWhitespaceLine(int startLine) |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
63 |
{ |
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
64 |
int prevLineIndex = startLine - 1; |
| |
65 |
var lineText = source.GetLine(prevLineIndex); |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
66 |
|
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
67 |
//searchig for not blank line |
| |
68 |
while (prevLineIndex > 0 && string.IsNullOrEmpty(lineText)) |
| |
69 |
{ |
| |
70 |
prevLineIndex--; |
| |
71 |
lineText = source.GetLine(prevLineIndex); |
| |
72 |
} |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
73 |
|
|
6dfa1b52
»
|
jagregory |
2008-10-12 |
Reimplemented smart indenti... |
74 |
return lineText; |
|
428d0a5d
»
|
jagregory |
2008-05-26 |
Implemented indenting and d... |
75 |
} |
| |
76 |
|
| |
77 |
/// <summary> |
| |
78 |
/// Determines whether the current line should have the newline indented. |
| |
79 |
/// </summary> |
| |
80 |
/// <param name="line">Current line</param> |
| |
81 |
/// <returns>Whether newline line should be indented</returns> |
| |
82 |
private bool RequiresIndent(string line) |
| |
83 |
{ |
| |
84 |
line = PrepareLine(line); // cheat and make parsing easier |
| |
85 |
|
| |
86 |
return line.EndsWith(":"); |
| |
87 |
} |
| |
88 |
|
| |
89 |
private bool RequiresDedent(string line) |
| |
90 |
{ |
| |
91 |
line = PrepareLine(line); // cheat and make parsing easier |
| |
92 |
Match dedentMatch = dedentRegExp.Match(line); |
| |
93 |
|
| |
94 |
// my regex foo is not strong enough to do this in one, so match |
| |
95 |
// a dedent line (i.e. return) but then check if it ends with an |
| |
96 |
// expression (i.e. return "value" if x = 10). Only indent if |
| |
97 |
// there isn't an expression |
| |
98 |
if (dedentMatch.Success && !dedentMatch.Groups["exp"].Success) |
| |
99 |
return true; |
| |
100 |
|
| |
101 |
return false; |
| |
102 |
} |
| |
103 |
|
| |
104 |
private string PrepareLine(string line) |
| |
105 |
{ |
| |
106 |
// remove comments, makes parsing easier |
| |
107 |
Match commentMatch = removeCommentsRegExp.Match(line); |
| |
108 |
|
| |
109 |
if (commentMatch != null && commentMatch.Groups.Count >= 2) |
| |
110 |
line = line.Remove(line.IndexOf(commentMatch.Groups[1].Value)); |
| |
111 |
|
| |
112 |
// get rid of trailing whitespace |
| |
113 |
line = line.TrimEnd(); |
| |
114 |
|
| |
115 |
return line; |
| |
116 |
} |
| |
117 |
} |
| |
118 |
} |