public void FormatCode(SnapshotSpan span, bool selectResult) { var snapshot = _view.TextBuffer.CurrentSnapshot; var ast = _view.GetAnalyzer().ParseFile(snapshot); var walker = new EnclosingNodeWalker(ast, span.Start, span.End); ast.Walk(walker); if (!walker.Target.IsValidSelection) { return; } var body = walker.Target.GetNode(ast); ITrackingSpan selectionSpan = null; if (selectResult) { selectionSpan = _view.TextBuffer.CurrentSnapshot.CreateTrackingSpan(span.Span, SpanTrackingMode.EdgeInclusive); } _view.ReplaceByLines( body.ToCodeString(ast, _format), Span.FromBounds(walker.Target.Start, walker.Target.End) ); if (selectResult) { _view.Selection.Select(selectionSpan.GetSpan(_view.TextBuffer.CurrentSnapshot), false); } }
internal void RemoveImports() { ScopeStatement targetStmt = null; if (!_allScopes) { var enclosingNodeWalker = new EnclosingNodeWalker(_ast, _view.Caret.Position.BufferPosition, _view.Caret.Position.BufferPosition + 1); _ast.Walk(enclosingNodeWalker); targetStmt = enclosingNodeWalker.Target.Parents[enclosingNodeWalker.Target.Parents.Length - 1]; } var walker = new ImportWalker(targetStmt); _ast.Walk(walker); using (var edit = _view.TextBuffer.CreateEdit()) { foreach (var removeInfo in walker.GetToRemove()) { // see if we're removing some or all of the //var node = removeInfo.Node; var removing = removeInfo.ToRemove; var removed = removeInfo.Statement; UpdatedStatement updatedStatement = removed.InitialStatement; int removeCount = 0; for (int i = 0, curRemoveIndex = 0; i < removed.NameCount; i++) { if (removed.IsRemoved(i, removing)) { removeCount++; updatedStatement = updatedStatement.RemoveName(_ast, curRemoveIndex); } else { curRemoveIndex++; } } var span = removed.Node.GetSpan(_ast); if (removeCount == removed.NameCount) { removeInfo.SiblingCount.Value--; DeleteStatement(edit, span, removeInfo.SiblingCount.Value == 0); } else { var newCode = updatedStatement.ToCodeString(_ast); int proceedingLength = (removed.Node.GetLeadingWhiteSpace(_ast) ?? "").Length; int start = span.Start.Index - proceedingLength; int length = span.Length + removed.Node.GetTrailingWhitespace(_ast).Length + proceedingLength; edit.Delete(start, length); edit.Insert(span.Start.Index, newCode); } } edit.Apply(); } }
public bool ExtractMethod(IExtractMethodInput input) { // tighten up the selection so that we don't expand into any enclosing nodes because we overlap w/ their white space... var selectionStart = _view.Selection.Start.Position; while (selectionStart.Position < _view.TextBuffer.CurrentSnapshot.Length && Char.IsWhiteSpace(selectionStart.GetChar())) { selectionStart += 1; } var selectionEnd = _view.Selection.End.Position; if (selectionEnd.Position == _view.TextBuffer.CurrentSnapshot.Length) { selectionEnd -= 1; } while (selectionEnd.Position >= 0 && Char.IsWhiteSpace(selectionEnd.GetChar())) { selectionEnd -= 1; } var walker = new EnclosingNodeWalker(_ast, selectionStart, selectionEnd); _ast.Walk(walker); Debug.Assert(walker.Target != null); // expand the selection if we aren't currently covering a full expression/statement if (!walker.Target.IsValidSelection || (WasSelectionExpanded(walker.Target, selectionStart, selectionEnd) && !input.ShouldExpandSelection())) { return false; } _view.Selection.Select( new SnapshotSpan( _view.TextBuffer.CurrentSnapshot, Span.FromBounds( walker.Target.Start, walker.Target.End ) ), false ); // check for things we cannot handle if (!IsValidExtraction(input, walker.Target)) { return false; } // get the variables which are read by the selected statement(s) var varCollector = new InnerVariableWalker(_ast); walker.Target.Walk(varCollector); // Walk the target to understand flow control and definite assignment to further understand // what we need to flow in. For example if a variable is assigned to both in the un-extracted // and extracted code but it's definitely assigned in the extracted code then we don't need // to flow the variable in. // Run flow checker, first on any nested scopes... foreach (ScopeStatement scope in varCollector._scopes) { FlowChecker.Check(scope); } // then on our extracted code var parent = walker.Target.Parents[walker.Target.Parents.Length - 1]; HashSet<JVariable> readBeforeInit; if (parent.ScopeVariables != null) { var flowChecker = new FlowChecker(parent); walker.Target.Walk(flowChecker); readBeforeInit = flowChecker.ReadBeforeInitializedVariables; } else { readBeforeInit = new HashSet<JVariable>(); } // then on code which follows our extracted body var afterStmts = walker.Target.GetStatementsAfter(_ast); HashSet<JVariable> readByFollowingCodeBeforeInit = null; var parentNode = walker.Target.Parents[walker.Target.Parents.Length - 1]; if (parentNode.ScopeVariables != null) { var checker = new FlowChecker(parentNode); foreach (var afterStmt in afterStmts) { afterStmt.Walk(checker); } readByFollowingCodeBeforeInit = checker.ReadBeforeInitializedVariables; } // discover any variables which are consumed and need to be available as outputs... var outputCollector = new OuterVariableWalker(_ast, walker.Target, varCollector, readBeforeInit, readByFollowingCodeBeforeInit); _ast.Walk(outputCollector); if (outputCollector._outputVars.Count > 0 && walker.Target.ContainsReturn) { input.CannotExtract("Cannot extract method that assigns to variables and returns"); return false; } var creator = new ExtractedMethodCreator( _ast, walker.Target.Parents, outputCollector._inputVars, outputCollector._outputVars, walker.Target, _view.Options.GetIndentSize(), !_view.Options.IsConvertTabsToSpacesEnabled() ); var info = input.GetExtractionInfo(creator); if (info == null) { // user cancelled extract method return false; } // get the new method body... var newMethod = creator.GetExtractionResult(info); // generate the call site. using (var edit = _view.TextBuffer.CreateEdit()) { // delete the selected code int start = _view.Selection.Start.Position; edit.Delete(Span.FromBounds(_view.Selection.Start.Position, _view.Selection.End.Position)); // insert the newly generated method edit.Insert(walker.Target.InsertLocations[info.TargetScope], newMethod.Method); // insert the call to the new method edit.Insert(start, newMethod.Call); edit.Apply(); } return true; }