[svn] r7795: vs-plugin/trunk: Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeFormattingStag...

kliss svnadmin at nemerle.org
Tue Sep 11 02:10:43 CEST 2007


Log:
Work on formatter.
Highlight paired braces whenever possible (from inner/outer side, when navigating with mouse, when navigating from upper/lower line with arrow keys)
Automatically insert/remove paired tokens (round, square, curly braces, and single/double quotes)
Fix some typos.

Author: kliss
Date: Tue Sep 11 02:09:46 2007
New Revision: 7795

Modified:
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeFormattingStageBase.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeIndentationStage.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeLineBreakingStage.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/Formatter.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/FormatterResult.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/NonEatingLexer.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ExprFinder.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Refactoring.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ScanLexer.n
   vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs
   vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs
   vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleSource.cs
   vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleTypeAndMemberDropdownBars .cs
   vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleViewFilter.cs
   vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileDocumentManager.cs
   vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleIdeBuildLogger.cs

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeFormattingStageBase.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeFormattingStageBase.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeFormattingStageBase.n	Tue Sep 11 02:09:46 2007
@@ -90,8 +90,14 @@
     protected _tokenFinder : TokenStreamHandler = TokenStreamHandler();
     
     private results : SCG.List.[FormatterResult] = SCG.List.[FormatterResult]();
+    
     protected AddResult(result : FormatterResult) : void
     {
+      // Ensure no conflicts
+      foreach(existingResult in results)
+        when(result.IntersectsWith(existingResult))
+          throw FormatterException($"Change $result conflicts with existing change $existingResult");
+
       results.Add(result);
     }
     protected GetResults() : SCG.List.[FormatterResult]

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeIndentationStage.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeIndentationStage.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeIndentationStage.n	Tue Sep 11 02:09:46 2007
@@ -110,7 +110,7 @@
         
         foreach(fr in results)
         {
-          when(fr.StartCol < col && fr.EndCol < col && fr.StartLine == fr.EndLine)
+          when(fr.StartCol < col && fr.EndCol <= col && fr.StartLine == fr.EndLine)
           {
             newCol += (fr.ReplacementString.Length - (fr.EndCol - fr.StartCol));
           }
@@ -127,7 +127,7 @@
     
     indentValue = " "; // TODO: make it configurable by user.
     defaultIndentSize = 2;
-    matchCasesIndentOffset = 2; // match cases will be indented by matchCasesIndentOffset * defaultIndentSize
+    matchCasesIndentOffset = 1; // match cases will be indented by matchCasesIndentOffset * defaultIndentSize
     matchCasesBodyIndentOffset = 2;
     variantOptionIndentOffset = 2;
         
@@ -174,7 +174,8 @@
 
         using(GetIndentPusher(PeekIndent() + matchCasesBodyIndentOffset * defaultIndentSize))
         {
-          cases.Map(_.body).Iter(FormatPExpr);
+          FormatPExpr(matchCase.body);
+          //cases.Map(_.body).Iter(FormatPExpr);
         }
       }
       
@@ -259,7 +260,7 @@
                 def beginBrace = _tokenFinder.FindAt(seq.Location.Line, seq.Location.Column);
                 assert(beginBrace is Token.BeginBrace);
                 
-                using(GetIndentPusher(RecalcLocation(firstKeywordLoc.UnSome()).Column))
+                using(GetIndentPusher(Math.Max(PeekIndent(), RecalcLocation(firstKeywordLoc.UnSome()).Column)))
                 {
                   IndentLocation(beginBrace.Location);
                   using(GetIndentPusher())
@@ -270,7 +271,7 @@
                 }
                 
             | _ => 
-                using(GetIndentPusher(RecalcLocation(firstKeywordLoc.UnSome()).Column + defaultIndentSize))
+                using(GetIndentPusher(Math.Max(PeekIndent(), RecalcLocation(firstKeywordLoc.UnSome()).Column + defaultIndentSize)))
                 {
                   FormatPExpr(pexpr);
                 }
@@ -287,12 +288,16 @@
                                                      | Token.Keyword as a when a.name == k => true
                                                      | _ => false;
                                                      });
+                    mutable preferredColumn = 0;
                     match(firstKeywordLoc)
                     {
-                    | None => firstKeywordLoc = Some(kw.Location);
-                    | _ => ()
+                    | None => 
+                        firstKeywordLoc = Some(kw.Location);
+                        preferredColumn = PeekIndent();
+                    | _ => preferredColumn = Math.Max(PeekIndent(), RecalcLocation(firstKeywordLoc.UnSome()).Column);
+
                     }
-                    using(GetIndentPusher(RecalcLocation(firstKeywordLoc.UnSome()).Column))
+                    using(GetIndentPusher(preferredColumn))
                     {
                       IndentLocation(kw.Location);
                     }
@@ -597,7 +602,8 @@
     
     FormatField(fb : FieldBuilder) : void
     {
-      Debug.Assert(fb.Location.Line == fb.Location.EndLine, $"Declaration of field $(fb.Name) spans over several lines. Can't indent.");
+      //Debug.Assert(fb.Location.Line == fb.Location.EndLine, $"Declaration of field $(fb.Name) spans over several lines. Can't indent.");
+      when(fb.Location.Line == fb.Location.EndLine)
       IndentLocation(fb.Location);
     }
     
@@ -670,7 +676,7 @@
   
         PushIndent();
         
-        foreach(member in tb.GetDirectMembers())
+        foreach(member in tb.GetDirectMembers().Filter(mmbr => mmbr.Location.FileIndex == _fileIndex))
           FormatTypeBuilderMember(member);
 
         _ = PopIndent();
@@ -736,7 +742,7 @@
     public override FormatRegion(startLine : int, startCol : int, endLine : int, endCol : int) : SCG.List.[FormatterResult]
     {
 _ = base.FormatRegion(startLine, startCol, endLine, endCol);
-// The call above sets "clipping" region, and FromatDocument will respect
+      // The call above sets "clipping" region, and FormatDocument will respect
 // this and will not make any changes that are not inside of that region.
 FormatDocument();
 }

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeLineBreakingStage.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeLineBreakingStage.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/CodeLineBreakingStage.n	Tue Sep 11 02:09:46 2007
@@ -126,7 +126,7 @@
 
         def matchFinder = MatchingBrackerFinder().GetSearchFunc(typeof(Token.EndBrace));
         def endBrace = _tokenFinder.FindNextIf(beginBrace.Location.Line, beginBrace.Location.EndColumn, matchFinder);
-        AddResult(FormatterResult.Insert(endBrace.Location.Line, endBrace.Location.Column, "/*endBrace*/"));   
+        //AddResult(FormatterResult.Insert(endBrace.Location.Line, endBrace.Location.Column, "/*endBrace*/"));   
         FormatBrace(endBrace);
 
         SetExpectedLine(endBrace.Location.EndLine + 1);

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/Formatter.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/Formatter.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/Formatter.n	Tue Sep 11 02:09:46 2007
@@ -12,6 +12,11 @@
 
 namespace Nemerle.Completion2.CodeFormatting
 {
+  /*
+      TODO: formatting stuff
+      format expression on semicolon
+      format block on closing curly brace
+  */
   public class Formatter
   {
     mutable _fileIndex : int = 0;
@@ -30,7 +35,13 @@
       Engine = engine;
       _fileIndex = fileIndex;
       _results = SCG.List.[FormatterResult]();
+    }
       
+    public this(engine : Engine, filePath : string)
+    {
+      Engine = engine;
+      _fileIndex = engine.Project.CompileUnits.GetFileIndex(filePath);
+      _results = SCG.List.[FormatterResult]();
     }
     
     
@@ -106,8 +117,6 @@
                       CodeIndentationStage(engine, fileIndex)
                     ];
                     
-      // TODO: After each stage send result to the VS,
-      // and wait for changes to be applied.
       foreach(stage in stages)
       {
         results.AddRange(stage.FormatDocument()); 
@@ -117,7 +126,6 @@
     
     }
     
-    // Here we have to find out what piece of AST to analyze
     public static FormatSpan( startLine : int, startCol : int, endLine : int, 
                               endCol : int, engine : Engine, filePath : string) : SCG.List[FormatterResult]
     {
@@ -126,19 +134,26 @@
       
       def stages : list[IFormattingStage] =  
                     [
-                      //CodeLineBreakingStage(engine, fileIndex)
+                      //CodeLineBreakingStage(engine, fileIndex),
                       CodeIndentationStage(engine, fileIndex)
                     ];
                     
-      // TODO: After each stage send result to the VS,
-      // and wait for changes to be applied.
       foreach(stage in stages)
-      {
-        
         results.AddRange(stage.FormatRegion(startLine, startCol, endLine, endCol)); 
-      }
 
       results;
     }
+
+    public static FormatExpressionAt(engine : Engine, filepath : string, line : int, col : int) : SCG.List[FormatterResult]
+    {
+      def results = SCG.List();
+      def rootDecl = engine.Project.CompileUnits[filepath];
+      def (loc, foundExpr) = ExprFinder().Find(rootDecl, line, col, 1);
+      //results.Add(FormatterResult.Insert(line, col, foundExpr.ToString()));
+      when(foundExpr != null && !loc.IsEmpty)
+        results.AddRange(FormatSpan(loc.Line, loc.Column, loc.EndLine, loc.EndColumn, engine, filepath));
+      results
+    }
+
   }
 }

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/FormatterResult.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/FormatterResult.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/FormatterResult.n	Tue Sep 11 02:09:46 2007
@@ -29,6 +29,12 @@
       }
     }
     
+    public IntersectsWith(other : FormatterResult) : bool
+    {
+      def thisLoc = Location(0, StartLine, StartCol, EndLine, EndCol);
+      thisLoc.Contains(other.StartLine, other.StartCol) || thisLoc.Contains(other.EndLine, other.EndCol);    
+    }
+    
     public static Replace(loc : Location, replacement : string) : FormatterResult 
     {
       FormatterResult(loc.Line, loc.Column, loc.EndLine, loc.EndColumn, replacement);

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/NonEatingLexer.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/NonEatingLexer.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeFormatting/NonEatingLexer.n	Tue Sep 11 02:09:46 2007
@@ -164,9 +164,9 @@
             get_number (ch)
           else
             if (IsIdBeginning (ch))
-              get_id (ch)
+              get_id (ch)  // '
             else
-              throw Error ($"invalid character: `$ch'")
+              throw Error ($"invalid character: '$ch'")
       }
     }
     

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ExprFinder.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ExprFinder.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ExprFinder.n	Tue Sep 11 02:09:46 2007
@@ -81,7 +81,7 @@
         {
           def texpr = GetTypedObject(obj);
 
-          when (texpr != null)
+          if (texpr != null)
           {
             when (_pexprObject == null || _location.Contains(loc))
             {
@@ -97,13 +97,23 @@
             {
             | PExpr.Wildcard => info.Stop();
             | PExpr.MacroCall(name, _, _) when IsIn(name.Location) =>
-
               _location = name.Location;
               info.Stop();
 
             | _ => ()
             }
           }
+          // Making it possible to find empty Sequence.
+          else match(obj)
+          {
+          | PExpr.Sequence([]) => 
+              _parentObject = _pexprObject;
+              _location     = loc;
+              _pexprObject  = info.Node;
+              _texprObject  = texpr;
+              info.Stop();
+          | _ => ()
+          }
         }
         else if (_line < loc.Line || _line == loc.Line && _col < loc.Column)
           info.Stop()
@@ -155,23 +165,63 @@
       }
     }
     
-    //// This method accepts Decl as a starting point.
-    //public Find(pRoot : Decl, line : int, col : int) : Location * object
-    //{
-    //  if(pRoot == null)
-    //   (Location.Default, null);
-    //  else
-    //  {
-    //     Init(line, col);
-    //     ExprWalker().Walk(pRoot, PFinder);
-    //     if(_pexprObject != null)
-    //       (_location, _pexprObject)
-    //     else if(_decl != null)
-    //      (_location, _decl);
-    //     else
-    //      (Location.Default, null);
-    //  }  
-    //}
+    // This method accepts Decl as a starting point.
+    public _Find(pRoot : Decl, line : int, col : int) : Location * object
+    {
+      if(pRoot == null)
+       (Location.Default, null);
+      else
+      {
+         Init(line, col);
+         ExprDeclWalker(this).Walk(pRoot, PFinder);
+         if(_pexprObject != null)
+           (_location, _pexprObject)
+         else if(_decl != null)
+          (_location, _decl);
+         else
+          (Location.Default, null);
+      }  
+    }
+    
+    // This method accepts Decl as a starting point.
+    public Find(pRoot : Decl, line : int, col : int, nthParentElement : int) : Location * object
+    {
+      def getLocation(obj : object)
+      {
+        if(obj is Located) 
+          (obj :> Located).Location 
+        else if(obj is IMember)
+          (obj :> IMember).Location
+        else if(obj is Decl)
+          (obj :> Decl).Location
+        else
+          Location.Default;      
+      }
+
+      if(pRoot == null)
+       (Location.Default, null);
+      else
+      {
+        Init(line, col);
+        ExprDeclWalker(this).Walk(pRoot, PFinder);
+        if(_walkedNodes.Length < nthParentElement)
+          (Location.Default, null)
+        else
+        {
+          if(_pexprObject != null)
+          {
+            match(_walkedNodes.Nth(nthParentElement))
+            {
+            | obj when getLocation(obj) != Location.Default => (getLocation(obj), obj)
+            | _ => (Location.Default, null)
+            }
+          }
+          else
+            (Location.Default, null)
+        }
+         
+      }  
+    }
     
     public Find(pRoot : PExpr, _tRoot : TExpr, line : int, col : int) : Location * object * object
     {

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Refactoring.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Refactoring.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Refactoring.n	Tue Sep 11 02:09:46 2007
@@ -284,7 +284,7 @@
         {
           Debug.WriteLine($"checking usage $usage for consistency");
           Debug.WriteLine($"must be member:\n $mustBeMember");
-          // phantom: strange, why it doesn't catch exeption on christianity.n, any interface member?
+          // phantom: strange, why it doesn't catch exception on christianity.n, any interface member?
           try
           {
             match (GetActiveDecl(usage.FileIndex, usage.Line, usage.Column))

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ScanLexer.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ScanLexer.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/ScanLexer.n	Tue Sep 11 02:09:46 2007
@@ -641,6 +641,7 @@
       {
         def tmp = _pendingToken;
         _pendingToken = null;
+        
         tmp;
       }
       else
@@ -873,6 +874,7 @@
     { 
       def chooseColor(str, regexList)
       {
+        
         match(regexList)
         {
         | (color, regex) :: xs =>
@@ -957,6 +959,7 @@
     {
       def mergeWithResult(result, newValue)
       {
+        
         match(newValue)
         {
         | x :: xs => result.Add(x); mergeWithResult(result, xs);
@@ -1049,6 +1052,7 @@
 
     _debug(obj : object) : void
     {
+     
       when (obj != null)
         _ = obj.ToString();
     }

Modified: vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs	Tue Sep 11 02:09:46 2007
@@ -407,7 +407,7 @@
 				return infos.ToArray();
 			}
 
-			// TODO: implement other languages then nemerle
+			// TODO: implement other languages than Nemerle
 
 			if (_findExactLocation && Path.GetExtension(infos[0].FilePath) == ".n")
 			{

Modified: vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs	Tue Sep 11 02:09:46 2007
@@ -595,19 +595,6 @@
 												false);
 		}
 
-		// TODO: Find out how to call this method on Escape.
-		private void RemoveLastHighlighting(ParseRequest request)
-		{
-			ProjectInfo projectInfo = GetProjectInfo(request);
-
-			if (projectInfo == null)
-				return;
-
-			if (Settings.Default.HighlightUsages)
-				if (!Settings.Default.HighlightUsagesUnlessTerminalSession || !NowIsTerminalSession())
-					projectInfo.RemoveLastHighlighting(new SourceTextManager(projectInfo.GetSource(request.FileName)));
-		}
- 
 		#endregion
 
 		#region GetCompleteWord
@@ -1011,6 +998,10 @@
 				_preferences.Init();
                 _preferences.EnableFormatSelection = true;
 
+				// TODO: Find out how to enable "Smart" radio option in 
+				// Tools->Options->Text editor->Nemerle->Tabs
+				_preferences.IndentStyle = IndentingStyle.Smart;
+
 #if DEBUG
 				//VladD2: Switch on synchronous mode for debugging purpose!
 				//TODO: Comment it if necessary.

Modified: vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleSource.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleSource.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleSource.cs	Tue Sep 11 02:09:46 2007
@@ -1,7 +1,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
-
+using System.Windows.Forms;
 using Microsoft.VisualStudio;
 using Microsoft.VisualStudio.Package;
 using Microsoft.VisualStudio.TextManager.Interop;
@@ -177,7 +177,7 @@
             //ReformatSpan_internal(mgr, span, engine, filePath);
             //base.ReformatSpan(mgr, span);
 		}
-        private void ReformatSpan_internal(EditArray _mgr, TextSpan span, Engine engine, string filePath)
+        private static void ReformatSpan_internal(EditArray _mgr, TextSpan span, Engine engine, string filePath)
         {
             List<FormatterResult> results =
                 Formatter.FormatSpan(span.iStartLine + 1,
@@ -211,6 +211,72 @@
 			return _methodData = base.CreateMethodData();
 		}
 
+		#region Paired chars insertion and deletion
+
+		// TODO: maybe refactor this part so that it will share code with BracketFinder
+		private readonly char[][] _pairedChars = new char[][]
+			{
+				new char[] {'{', '}'},
+				new char[] {'(', ')'},
+				new char[] {'\'', '\''},
+				new char[] {'[', ']'},
+				new char[] {'"', '"'}
+			};
+
+		private bool IsOpeningPairedChar(char ch)
+		{
+			foreach (char[] charPair in _pairedChars)
+			{
+				if(charPair[0] == ch)
+					return true;
+			}
+			return false;
+		}
+
+		private bool IsClosingPairedChar(char ch)
+		{
+			foreach (char[] charPair in _pairedChars)
+			{
+				if(charPair[1] == ch)
+					return true;
+			}
+			return false;
+		}
+		
+		private char GetClosingChar(char ch)
+		{
+			foreach (char[] charPair in _pairedChars)
+			{
+				if(charPair[0] == ch)
+					return charPair[1];
+			}
+			throw new ApplicationException("Paired char not found for '" + ch + "'");
+		}
+
+		private char _rememberedChar;
+
+		public void RememberCharBeforeCaret(IVsTextView textView)
+		{
+			int line;
+			int idx;
+			textView.GetCaretPos(out line, out idx);
+			if(idx > 0)
+				_rememberedChar = GetText(line, idx - 1, line, idx)[0];
+		}
+
+		public void ClearRememberedChar()
+		{
+			_rememberedChar = (char) 0;
+		}
+
+
+		#endregion
+
+		private void RemoveCharAt(int line, int idx)
+		{
+			SetText(line, idx, line, idx + 1, "");
+		}
+
 		public override void OnCommand(IVsTextView textView, VsCommands2K command, char ch)
 		{
 			if (textView == null || _service == null || !_service.Preferences.EnableCodeSense)
@@ -220,34 +286,88 @@
 				command == VsCommands2K.LEFT || command == VsCommands2K.LEFT_EXT);
 
 			int line, idx;
-
 			textView.GetCaretPos(out line, out idx);
 
-			TokenInfo     info         = GetTokenInfo(line, idx);
-			TokenTriggers triggerClass = info.Trigger;
+			TokenInfo tokenBeforeCaret = GetTokenInfo(line, idx);
+			TokenInfo tokenAfterCaret = GetTokenInfo(line, idx + 1);
 
-			if ((triggerClass & TokenTriggers.MemberSelect) != 0 && (command == VsCommands2K.TYPECHAR))
+			HandlePairedSymbols(textView, command, line, idx, ch);
+
+			if ((tokenBeforeCaret.Trigger & TokenTriggers.MemberSelect) != 0 && (command == VsCommands2K.TYPECHAR))
 			{
-				ParseReason reason = ((triggerClass & TokenTriggers.MatchBraces) == TokenTriggers.MatchBraces) ?
+				ParseReason reason = ((tokenBeforeCaret.Trigger & TokenTriggers.MatchBraces) == TokenTriggers.MatchBraces) ?
 					ParseReason.MemberSelectAndHighlightBraces :
 					ParseReason.MemberSelect;
 
-				this.Completion(textView, info, reason);
+				Completion(textView, tokenBeforeCaret, reason);
+			}
+			TryHighlightBraces(textView, command, line, idx, tokenBeforeCaret, tokenAfterCaret);
+
+			if (!_methodData.IsDisplayed &&
+				(tokenBeforeCaret.Trigger & TokenTriggers.MethodTip) != 0 &&
+				command == VsCommands2K.TYPECHAR &&
+				_service.Preferences.ParameterInformation)
+			{
+				MethodTip(textView, line, idx, tokenBeforeCaret);
+			}
 			}
-			else if ((triggerClass & TokenTriggers.MatchBraces) != 0 && _service.Preferences.EnableMatchBraces)
+
+		private void TryHighlightBraces(IVsTextView textView, VsCommands2K command, int line, int idx,
+		                                TokenInfo tokenInfo)
+		{
+			// Highlight brace to the left from the caret
+			if ((tokenInfo.Trigger & TokenTriggers.MatchBraces) != 0 && _service.Preferences.EnableMatchBraces)
 			{
-				if ((command != VsCommands2K.BACKSPACE) && ((command == VsCommands2K.TYPECHAR) || _service.Preferences.EnableMatchBracesAtCaret))
+				if ( (command != VsCommands2K.BACKSPACE) && 
+				    (/*(command == VsCommands2K.TYPECHAR) ||*/ 
+					_service.Preferences.EnableMatchBracesAtCaret)) 
 				{
-					this.MatchBraces(textView, line, idx, info);
+					MatchBraces(textView, line, idx, tokenInfo);
 				}
 			}
+		}
+		private void TryHighlightBraces(IVsTextView textView, VsCommands2K command, int line, int idx,
+		                                TokenInfo tokenBeforeCaret, TokenInfo tokenAfterCaret)
+		{
+			TryHighlightBraces(textView, command, line, idx + 1, tokenAfterCaret);
+			TryHighlightBraces(textView, command, line, idx, tokenBeforeCaret);
+		}
 
-			if (!_methodData.IsDisplayed &&
-				(triggerClass & TokenTriggers.MethodTip) != 0 &&
-				command == VsCommands2K.TYPECHAR &&
-				_service.Preferences.ParameterInformation)
+		public void TryHighlightBraces(IVsTextView textView)
+		{
+			int line, idx;
+			textView.GetCaretPos(out line, out idx);
+
+			TokenInfo tokenBeforeCaret = GetTokenInfo(line, idx);
+			TokenInfo tokenAfterCaret = GetTokenInfo(line, idx + 1);
+			TryHighlightBraces(textView, VsCommands2K.UP, line, idx, tokenBeforeCaret, tokenAfterCaret);
+		}
+
+		private void HandlePairedSymbols(IVsTextView textView, VsCommands2K command, int line, int idx, char ch)
+		{
+			// insert paired symbols here
+			if(command == VsCommands2K.TYPECHAR)
+			{
+				if(IsOpeningPairedChar(ch))
+				{
+					SetText(line, idx, line, idx, GetClosingChar(ch).ToString());
+					textView.SetCaretPos(line, idx);
+				}
+				// if we just typed closing char and the char after caret is the same then we just remove 
+				// one of them
+				if(IsClosingPairedChar(ch))
+				{
+					char charAfterCaret = GetText(line, idx, line, idx + 1)[0];
+					if (ch == charAfterCaret/*IsClosingPairedChar(charAfterCaret)*/)
+						RemoveCharAt(line, idx);
+				}
+			}
+			// delete closing char if opened char was just backspaced and closing one is right next
+			if(command == VsCommands2K.BACKSPACE)
 			{
-				MethodTip(textView, line, idx, info);
+				char closingChar = GetText(line, idx, line, idx + 1)[0];
+				if(IsOpeningPairedChar(_rememberedChar) && IsClosingPairedChar(closingChar))
+					RemoveCharAt(line, idx);
 			}
 		}
 

Modified: vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleTypeAndMemberDropdownBars .cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleTypeAndMemberDropdownBars .cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleTypeAndMemberDropdownBars .cs	Tue Sep 11 02:09:46 2007
@@ -39,10 +39,10 @@
 			ref int               selectedMember)
 		{
 			if (_source.ProjectInfo == null)
-				//TODO: Use fake (cached) Project for parcing purpose
-				//      if file not in any project. It's allow show combo box
+				//TODO: Use fake (cached) Project for parsing purpose
+				//      if file not in any project. It allows showing combo box
 				//      for standalone files. We shold cache Project because
-				//      it creation is expensive operation.
+				//      its creation is expensive operation.
 				return false;
 
 			bool ret = false;

Modified: vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleViewFilter.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleViewFilter.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleViewFilter.cs	Tue Sep 11 02:09:46 2007
@@ -12,6 +12,7 @@
 
 using Nemerle.Completion2;
 using Nemerle.Compiler;
+using Nemerle.Completion2.CodeFormatting;
 using Nemerle.VisualStudio.Project;
 using Nemerle.VisualStudio.GUI;
 
@@ -55,6 +56,7 @@
 			int iMinUnit, int iMaxUnits, int iVisibleUnits, int iFirstVisibleUnit)
 		{
 			base.OnChangeScrollInfo(view, iBar, iMinUnit, iMaxUnits, iVisibleUnits, iFirstVisibleUnit);
+			Source.TryHighlightBraces(view);
 			ShowAst(view, false);
 		}
 
@@ -306,7 +308,7 @@
             // one extra line is added to the selection (where the caret is left)
             TextSpan ts = new TextSpan();
 	        TextView.GetSelection(out ts.iStartLine, out ts.iStartIndex, out ts.iEndLine, out ts.iEndIndex);
-	        if (ts.iEndIndex == 0)
+	        if (ts.iEndIndex == 0 && ts.iEndLine - ts.iStartLine > 0)
 	            ts.iEndLine--;
 	        return ts;
 	    }
@@ -314,6 +316,15 @@
 	    public override bool HandlePreExec(
 			ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
 		{
+			VsCommands2K cmd = (VsCommands2K)nCmdId;
+			
+			// we're goona to erase some symbol from existence. 
+			// In some cases we need to know what it was (auto-deletion of paired token)
+			if (cmd == VsCommands2K.BACKSPACE)
+				Source.RememberCharBeforeCaret(TextView);
+			else
+				Source.ClearRememberedChar();
+
 			_startLine = -1;
 
 			if (guidCmdGroup == VSConstants.VSStd2K)
@@ -321,12 +332,12 @@
 				if (Source.MethodData.IsDisplayed)
 					TextView.GetCaretPos(out _startLine, out _startPos);
 
-				VsCommands2K cmd = (VsCommands2K)nCmdId;
+
 
 				switch (cmd)
 				{
 					case VsCommands2K.FORMATSELECTION:
-						this.ReformatSelection();
+						ReformatSelection();
 						return true;
 
 					case VsCommands2K.INSERTSNIPPET:
@@ -338,10 +349,6 @@
 
 							return true; // Handled the command.
 						}
-
-                    case VsCommands2K.COMMENT_BLOCK:
-                        CommentSelection();
-                        return true;
 					case VsCommands2K.SURROUNDWITH:
 						{
 							ExpansionProvider ep = GetExpansionProvider();
@@ -359,7 +366,7 @@
 
 							if (count > 1)
 							{
-								while (Source.MethodData.NextMethod() < count - 1) ;
+								while (Source.MethodData.NextMethod() < count - 1) 
 								Source.MethodData.UpdateView();
 
 								return true;
@@ -375,7 +382,7 @@
 
 							if (count > 1 && Source.MethodData.GetCurMethod() == count - 1)
 							{
-								while (Source.MethodData.PrevMethod() > 0) ;
+								while (Source.MethodData.PrevMethod() > 0) 
 								Source.MethodData.UpdateView();
 
 								return true;
@@ -391,20 +398,52 @@
 			return base.HandlePreExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
 		}
 
+		// TODO: Implement smart indention
+		// 1. When typing open curly brace (second is entered automatically) and 
+		//		then pressing enter
+		// 2. When typing enter between sentences.
+		// 3. When typing enter in the middle of expression.
+		public override bool HandleSmartIndent()
+		{
+			// TODO: Minimal functionality is to find what caret position should be,
+			// and to insert needed whitespace to move all the text that is after caret
+			// to the position after preferred caret position.
+
+			int line;
+			int idx;
+			TextView.GetCaretPos(out line, out idx);
+			
+			string filePath = Source.GetFilePath();
+			ProjectInfo projectInfo = ProjectInfo.FindProject(filePath);
+			Engine engine = projectInfo.Engine;
+
+			List<FormatterResult> results = Formatter.FormatExpressionAt(engine, filePath, line + 1, idx + 1);
+			ApplyFormatterResults(results);
+
+			//MessageBox.Show("Caret pos in HandleSmartIndent: " + line + ":" + col);
+			return false;
+		}
+
 		public override void HandlePostExec(
 			ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut, bool bufferWasChanged)
 		{
+			VsCommands2K cmd = (VsCommands2K)nCmdId;
 			// Special handling of "Toggle all outlining" command
-			//if (guidCmdGroup == typeof(VsCommands2K).GUID)
-			//{
-			//	if ((VsCommands2K)nCmdId == VsCommands2K.OUTLN_TOGGLE_ALL)
-			//	{
-			//		Source.CollapseAllRegions();
-			//		return;
-			//	}
-			//}
+			/*if (guidCmdGroup == typeof(VsCommands2K).GUID)
+			{
+				if ((VsCommands2K)nCmdId == VsCommands2K.OUTLN_TOGGLE_ALL)
+				{
+					Source.CollapseAllRegions();
+					return;
+				}
+			}
+*/
 			base.HandlePostExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut, bufferWasChanged);
 
+			// workaround: for some reason, UP and DOWN commands are not passed to Source in base.HandlePostExec
+			if (cmd == VsCommands2K.UP || cmd == VsCommands2K.DOWN)
+				Source.OnCommand(TextView, cmd, '\0');
+			
 			if (_startLine >= 0 && Source.MethodData.IsDisplayed)
 			{
 				int line;
@@ -414,8 +453,6 @@
 
 				if (line != _startLine || pos != _startPos)
 				{
-					VsCommands2K cmd = (VsCommands2K)nCmdId;
-
 					bool backward =
 						cmd == VsCommands2K.BACKSPACE ||
 						cmd == VsCommands2K.BACKTAB ||
@@ -437,6 +474,23 @@
 			}
 		}
 
+		private void ApplyFormatterResults(List<FormatterResult> results)
+		{
+			foreach (FormatterResult result in results)
+			{
+				if(result.StartLine == result.EndLine)
+				{
+					int line = result.StartLine - 1;
+					Debug.Assert(Source.GetLineLength(line) >= result.EndCol - 1, "Line must be GE that formatter result");
+					Source.SetText(line, result.StartCol - 1, line, result.EndCol - 1,
+								   result.ReplacementString);
+				}
+				else
+					Source.SetText(result.StartLine, result.StartCol - 1, result.EndLine - 1, result.EndCol - 1,
+				               result.ReplacementString);
+			}
+		}
+
 		/// <summary>
 		/// Here we will do our formatting...
 		/// </summary>

Modified: vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileDocumentManager.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileDocumentManager.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileDocumentManager.cs	Tue Sep 11 02:09:46 2007
@@ -14,7 +14,7 @@
 
 		public override int Open(bool newFile, bool openWith, ref Guid logicalView, IntPtr docDataExisting, out Microsoft.VisualStudio.Shell.Interop.IVsWindowFrame windowFrame, WindowFrameShowAction windowFrameAction)
 		{
-			//TODO: It's not bast way to find project. NemerleFileDocumentManager must contains reference to ProjectInfo.
+			//TODO: It's not best way to find project. NemerleFileDocumentManager must contain reference to ProjectInfo.
 			ProjectInfo projectInfo = ProjectInfo.FindProject(GetFullPathForDocument());
 			
 			if (projectInfo != null)

Modified: vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleIdeBuildLogger.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleIdeBuildLogger.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleIdeBuildLogger.cs	Tue Sep 11 02:09:46 2007
@@ -24,13 +24,13 @@
 	internal class NemerleIdeBuildLogger : Logger
 	{
 		#region fields
-		// TODO: Remove these constants when we have a version that suppoerts 
+		// TODO: Remove these constants when we have a version that supports 
 		//   getting the verbosity using automation.
 		private string _buildVerbosityRegistryRoot;
 		private const string BuildVerbosityRegistrySubKey = @"General";
 		private const string BuildVerbosityRegistryKey = "MSBuildLoggerVerbosity";
 		// TODO: Re-enable this constants when we have a version that 
-		//   suppoerts getting the verbosity using automation.
+		//   supports getting the verbosity using automation.
 		//private const string EnvironmentCategory = "Environment";
 		//private const string ProjectsAndSolutionSubCategory = "ProjectsAndSolution";
 		//private const string BuildAndRunPage = "BuildAndRun";



More information about the svn mailing list