jagregory / boolangstudio forked from olsonjeffery/boolangstudio

Boo language integration for Visual Studio 2008

This URL has Read+Write access

boolangstudio / Source / BooLangService / LineIndenter.cs
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 }