@Override
  public void run() {
    ITextSelection ts = (ITextSelection) editor.getSelectionProvider().getSelection();
    line = ts.getEndLine();
    try {
      terminateWithSemicolon();
      boolean changed;
      int count = 0;
      do {
        changed = terminateWithBrace();
        count++;
      } while (changed && count < 5);

      //			change = new DocumentChange("Terminate Statement", doc);
      //			change.setEdit(new MultiTextEdit());
      //			editor.getParseController().parse(doc, new NullProgressMonitor(), null);
      //			terminateWithParen(doc, change);
      //			change.perform(new NullProgressMonitor());

      editor.scheduleParsing();

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 private CeylonParseController parse() {
   CeylonParseController cpc = new CeylonParseController();
   cpc.initialize(
       editor.getParseController().getPath(), editor.getParseController().getProject(), null);
   cpc.parse(editor.getCeylonSourceViewer().getDocument(), new NullProgressMonitor(), null);
   return cpc;
 }
  private boolean terminateWithSemicolon() throws Exception {
    final IDocument doc = editor.getCeylonSourceViewer().getDocument();
    final TextChange change = new DocumentChange("Terminate Statement", doc);
    change.setEdit(new MultiTextEdit());
    CeylonParseController parser = parse();
    CompilationUnit rootNode = parser.getRootNode();
    IRegion li = getLineInfo(doc);
    String lineText = doc.get(li.getOffset(), li.getLength());
    final List<CommonToken> tokens = parser.getTokens();
    // final int startOfCodeInLine = getCodeStart(li, lineText, tokens);
    final int endOfCodeInLine = getCodeEnd(li, lineText, tokens);
    if (!doc.get(endOfCodeInLine, 1).equals(";")) {
      new Processor() {
        @Override
        public void visit(Tree.Annotation that) {
          super.visit(that);
          terminateWithSemicolon(that);
        }

        @Override
        public void visit(Tree.StatementOrArgument that) {
          super.visit(that);
          if (that instanceof Tree.ExecutableStatement && !(that instanceof Tree.ControlStatement)
              || that instanceof Tree.AttributeDeclaration
              || that instanceof Tree.MethodDeclaration
              || that instanceof Tree.ClassDeclaration
              || that instanceof Tree.InterfaceDeclaration
              || that instanceof Tree.SpecifiedArgument) {
            terminateWithSemicolon(that);
          }
        }

        private void terminateWithSemicolon(Node that) {
          try {
            if (that.getStartIndex() <= endOfCodeInLine && that.getStopIndex() >= endOfCodeInLine) {
              Token et = that.getEndToken();
              if (et == null
                  || et.getType() != CeylonLexer.SEMICOLON
                  || that.getStopIndex() > endOfCodeInLine) {
                if (!change.getEdit().hasChildren()) {
                  change.addEdit(new InsertEdit(endOfCodeInLine + 1, ";"));
                }
              }
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }.visit(rootNode);
      if (change.getEdit().hasChildren()) {
        change.perform(new NullProgressMonitor());
        return true;
      }
    }
    return false;
  }
  private boolean terminateWithBrace() throws Exception {
    IDocument doc = editor.getCeylonSourceViewer().getDocument();
    final TextChange change = new DocumentChange("Terminate Statement", doc);
    change.setEdit(new MultiTextEdit());
    CeylonParseController parser = parse();
    CompilationUnit rootNode = parser.getRootNode();
    IRegion li = getLineInfo(doc);
    final String lineText = doc.get(li.getOffset(), li.getLength());
    final List<CommonToken> tokens = parser.getTokens();
    final int startOfCodeInLine = getCodeStart(li, lineText, tokens);
    final int endOfCodeInLine = getCodeEnd(li, lineText, tokens);
    new Processor() {
      @Override
      public void visit(Tree.Expression that) {
        super.visit(that);
        if (that.getStopIndex() <= endOfCodeInLine && that.getStartIndex() >= startOfCodeInLine) {
          Token et = that.getMainEndToken();
          Token st = that.getMainToken();
          if (st != null
              && st.getType() == CeylonLexer.LPAREN
              && (et == null || et.getType() != CeylonLexer.RPAREN)) {
            if (!change.getEdit().hasChildren()) {
              change.addEdit(new InsertEdit(that.getStopIndex() + 1, ")"));
            }
          }
        }
      }

      @Override
      public void visit(Tree.ParameterList that) {
        super.visit(that);
        terminate(that, CeylonLexer.RPAREN, ")");
      }

      public void visit(Tree.IndexExpression that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACKET, "]");
      }

      @Override
      public void visit(Tree.TypeParameterList that) {
        super.visit(that);
        terminate(that, CeylonLexer.LARGER_OP, ">");
      }

      @Override
      public void visit(Tree.TypeArgumentList that) {
        super.visit(that);
        terminate(that, CeylonLexer.LARGER_OP, ">");
      }

      @Override
      public void visit(Tree.PositionalArgumentList that) {
        super.visit(that);
        if (that.getToken().getType() == CeylonLexer.LPAREN) { // for infix function syntax
          terminate(that, CeylonLexer.RPAREN, ")");
        }
      }

      @Override
      public void visit(Tree.NamedArgumentList that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACE, " }");
      }

      @Override
      public void visit(Tree.SequenceEnumeration that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACE, " }");
      }

      @Override
      public void visit(Tree.IterableType that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACE, "}");
      }

      @Override
      public void visit(Tree.Tuple that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACKET, "]");
      }

      @Override
      public void visit(Tree.TupleType that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACKET, "]");
      }

      @Override
      public void visit(Tree.ConditionList that) {
        super.visit(that);
        initiate(that, CeylonLexer.LPAREN, "(");
        // does not really work right:
        terminate(that, CeylonLexer.RPAREN, ")");
      }

      @Override
      public void visit(Tree.ForIterator that) {
        super.visit(that);
        initiate(that, CeylonLexer.LPAREN, "(");
        // does not really work right:
        terminate(that, CeylonLexer.RPAREN, ")");
      }

      @Override
      public void visit(Tree.ImportMemberOrTypeList that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACE, " }");
      }

      @Override
      public void visit(Tree.ImportModule that) {
        super.visit(that);
        terminate(that, CeylonLexer.SEMICOLON, ";");
      }

      @Override
      public void visit(Tree.ImportModuleList that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACE, " }");
      }

      @Override
      public void visit(Tree.PackageDescriptor that) {
        super.visit(that);
        terminate(that, CeylonLexer.SEMICOLON, ";");
      }

      @Override
      public void visit(Tree.Body that) {
        super.visit(that);
        terminate(that, CeylonLexer.RBRACE, " }");
      }

      @Override
      public void visit(Tree.StatementOrArgument that) {
        super.visit(that);
        if (
        /*that instanceof Tree.ExecutableStatement &&
        	!(that instanceof Tree.ControlStatement) ||
        that instanceof Tree.AttributeDeclaration ||
        that instanceof Tree.MethodDeclaration ||
        that instanceof Tree.ClassDeclaration ||
        that instanceof Tree.InterfaceDeclaration ||*/
        that instanceof Tree.SpecifiedArgument) {
          terminate(that, CeylonLexer.SEMICOLON, ";");
        }
      }

      private void initiate(Node that, int tokenType, String ch) {
        if (that.getStartIndex() >= startOfCodeInLine && that.getStartIndex() <= endOfCodeInLine) {
          Token et = that.getMainToken();
          if (et == null || et.getType() != tokenType || et.getText().startsWith("<missing ")) {
            if (!change.getEdit().hasChildren()) {
              change.addEdit(new InsertEdit(that.getStartIndex(), ch));
            }
          }
        }
      }

      private void terminate(Node that, int tokenType, String ch) {
        if (that.getStartIndex() >= startOfCodeInLine && that.getStartIndex() <= endOfCodeInLine) {
          Token et = that.getMainEndToken();
          if ((et == null || et.getType() != tokenType) || that.getStopIndex() > endOfCodeInLine) {
            if (!change.getEdit().hasChildren()) {
              change.addEdit(new InsertEdit(min(endOfCodeInLine, that.getStopIndex()) + 1, ch));
            }
          }
        }
      }
    }.visit(rootNode);
    if (change.getEdit().hasChildren()) {
      change.perform(new NullProgressMonitor());
      return true;
    }
    return false;
  }