* merge with HEAD
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/docs/RiHelper.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/docs/RiHelper.java
index f515e71..489e3d6 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/docs/RiHelper.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/docs/RiHelper.java
@@ -69,7 +69,7 @@
 				.append("dltkri.rb").toFile();
 		riProcess = ScriptLaunchUtil.runScriptWithInterpreter(install
 				.getInstallLocation().getAbsolutePath(), script, null, null,
-				null);
+				null, install.getEnvironmentVariables());
 
 		writer = new OutputStreamWriter(riProcess.getOutputStream());
 		reader = new BufferedReader(new InputStreamReader(riProcess
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/documentation/RubyDocumentationProvider.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/documentation/RubyDocumentationProvider.java
index a554a7d..008c2ad 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/documentation/RubyDocumentationProvider.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/documentation/RubyDocumentationProvider.java
@@ -52,6 +52,7 @@
 	 */
 	private static void installStuff(Document document) {
 		String[] types = new String[] { IRubyPartitions.RUBY_STRING,
+				IRubyPartitions.RUBY_SINGLE_QUOTE_STRING,
 				IRubyPartitions.RUBY_COMMENT, IRubyPartitions.RUBY_DOC,
 				IDocument.DEFAULT_CONTENT_TYPE };
 		FastPartitioner partitioner = new FastPartitioner(
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/editor/RubyEditor.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/editor/RubyEditor.java
index 57ade30..308b7e4 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/editor/RubyEditor.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/editor/RubyEditor.java
@@ -30,8 +30,11 @@
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IDocumentExtension3;
+import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ITextOperationTarget;
 import org.eclipse.jface.text.ITextViewerExtension;
+import org.eclipse.jface.text.ITextViewerExtension5;
+import org.eclipse.jface.text.source.ICharacterPairMatcher;
 import org.eclipse.jface.text.source.ISourceViewer;
 import org.eclipse.jface.text.source.SourceViewerConfiguration;
 import org.eclipse.swt.widgets.Composite;
@@ -205,4 +208,70 @@
 		super.configureSourceViewerDecorationSupport(support);
 	}
 	
+	/**
+	 * Jumps to the matching bracket.
+	 */
+	public void gotoMatchingBracket() {
+		ISourceViewer sourceViewer = getSourceViewer();
+		IDocument document = sourceViewer.getDocument();
+		if (document == null)
+			return;
+
+		IRegion selection = getSignedSelection(sourceViewer);
+
+		int selectionLength = Math.abs(selection.getLength());
+		if (selectionLength > 1) {
+			setStatusLineErrorMessage("No bracket selected");
+			sourceViewer.getTextWidget().getDisplay().beep();
+			return;
+		}
+
+		// #26314
+		int sourceCaretOffset = selection.getOffset() + selection.getLength();
+		if (isSurroundedByBrackets(document, sourceCaretOffset))
+			sourceCaretOffset -= selection.getLength();
+		
+		IRegion region = bracketMatcher.match(document, sourceCaretOffset);
+		if (region == null) {
+			setStatusLineErrorMessage("No matching bracket found");
+			sourceViewer.getTextWidget().getDisplay().beep();
+			return;
+		}
+
+		int offset = region.getOffset();
+		int length = region.getLength();
+
+		if (length < 1)
+			return;
+
+		int anchor = bracketMatcher.getAnchor();
+		// http://dev.eclipse.org/bugs/show_bug.cgi?id=34195
+		int targetOffset = (ICharacterPairMatcher.RIGHT == anchor) ? offset + 1
+				: offset + length;
+
+		boolean visible = false;
+		if (sourceViewer instanceof ITextViewerExtension5) {
+			ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer;
+			visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1);
+		} else {
+			IRegion visibleRegion = sourceViewer.getVisibleRegion();
+			// http://dev.eclipse.org/bugs/show_bug.cgi?id=34195
+			visible = (targetOffset >= visibleRegion.getOffset() && targetOffset <= visibleRegion
+					.getOffset()
+					+ visibleRegion.getLength());
+		}
+
+		if (!visible) {
+			setStatusLineErrorMessage("Matching bracket is outside selected element");
+			sourceViewer.getTextWidget().getDisplay().beep();
+			return;
+		}
+
+		if (selection.getLength() < 0)
+			targetOffset -= selection.getLength();
+
+		sourceViewer.setSelectedRange(targetOffset, selection.getLength());
+		sourceViewer.revealRange(targetOffset, selection.getLength());
+	}
+	
 }
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/IRubyPartitions.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/IRubyPartitions.java
index e56613b..7f2d153 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/IRubyPartitions.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/IRubyPartitions.java
@@ -8,9 +8,11 @@
 
 	public static final String RUBY_COMMENT = "__ruby_comment";
 	public static final String RUBY_STRING = "__ruby_string";
+	public static final String RUBY_SINGLE_QUOTE_STRING = "__ruby_single_quote_string";
 	public static final String RUBY_DOC = "__ruby_doc";
 
 	public final static String[] RUBY_PARTITION_TYPES = new String[] {
 			IDocument.DEFAULT_CONTENT_TYPE, IRubyPartitions.RUBY_DOC,
-			IRubyPartitions.RUBY_COMMENT, IRubyPartitions.RUBY_STRING };
+			IRubyPartitions.RUBY_COMMENT, IRubyPartitions.RUBY_STRING,
+			IRubyPartitions.RUBY_SINGLE_QUOTE_STRING };
 }
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyAutoEditStrategy.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyAutoEditStrategy.java
index 4329e22..6c480d6 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyAutoEditStrategy.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyAutoEditStrategy.java
@@ -2,13 +2,6 @@
 
 import java.util.Arrays;
 
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.dltk.ast.parser.ISourceParser;
-import org.eclipse.dltk.compiler.problem.IProblem;
-import org.eclipse.dltk.compiler.problem.IProblemReporter;
-import org.eclipse.dltk.core.DLTKLanguageManager;
-import org.eclipse.dltk.ruby.core.RubyNature;
 import org.eclipse.dltk.ruby.internal.ui.RubyUI;
 import org.eclipse.dltk.ui.DLTKUIPlugin;
 import org.eclipse.dltk.ui.text.util.AutoEditUtils;
@@ -73,7 +66,7 @@
 	private String getApropriateBlockEnding(IDocument d,
 			RubyHeuristicScanner scanner, int offset)
 			throws BadLocationException {
-		int beginning = scanner.findBlockBeginningOffset(offset);
+		int beginning = scanner.findBlockBeginningOffset(offset) - 1;
 		IRegion line = d.getLineInformationOfOffset(beginning);
 		int ending = Math.min(line.getOffset() + line.getLength(), offset);
 		int token = scanner.previousToken(ending, beginning);
@@ -128,7 +121,7 @@
 		if (Arrays.binarySearch(INDENT_TO_BLOCK_TOKENS, token) >= 0) {
 			String indent = "";
 			try {
-				indent = getBlockIndent(d, c, scanner);
+				indent = getBlockIndent(d, info.getOffset(), scanner);
 			} catch (BadLocationException e) {
 				// there is no enclosing block
 			}
@@ -150,13 +143,34 @@
 			c.text = d.get(start, c.offset - start) + c.text;
 			c.length = c.offset - info.getOffset();
 			c.offset = info.getOffset();
+		} else {
+			// if previous was indented to block, restore original indentation
+			int wsPos = scanner.findNonIdentifierBackward(c.offset, info
+					.getOffset());
+			int previosToken = scanner.previousToken(c.offset, wsPos);
+			if (Arrays.binarySearch(INDENT_TO_BLOCK_TOKENS, previosToken) >= 0
+					&& Character.isJavaIdentifierPart(c.text.charAt(0))) {
+				String indent = getPreviousLineIndent(d, info.getOffset() - 1,
+						scanner);
+
+				int pos = scanner.findNonWhitespaceForwardInAnyPartition(info
+						.getOffset(), c.offset);
+				String line = "";
+				if (pos != RubyHeuristicScanner.NOT_FOUND) {
+					line = d.get(pos, c.offset - pos);
+				}
+
+				c.text = indent + line + c.text;
+				c.length = c.offset - info.getOffset();
+				c.offset = info.getOffset();
+			}
 		}
 	}
 
-	private String getBlockIndent(IDocument d, DocumentCommand c,
+	private String getBlockIndent(IDocument d, int offset,
 			RubyHeuristicScanner scanner) throws BadLocationException {
 
-		int blockOffset = scanner.findBlockBeginningOffset(c.offset);
+		int blockOffset = scanner.findBlockBeginningOffset(offset);
 		if (blockOffset == RubyHeuristicScanner.NOT_FOUND)
 			throw new BadLocationException("Block not found");
 
@@ -182,7 +196,7 @@
 		// beginning
 		if (nextIsIdentToBlockToken(scanner, c.offset, lineEnd)) {
 			try {
-				c.text += getBlockIndent(d, c, scanner);
+				c.text += getBlockIndent(d, c.offset, scanner);
 			} catch (BadLocationException e) {
 				// there is no enclosing block
 			}
@@ -190,7 +204,7 @@
 		}
 
 		// else
-		String indent = getPreviousLineIndent(d, c, scanner);
+		String indent = getPreviousLineIndent(d, c.offset, scanner);
 		c.text += indent;
 
 		if (previousIsBlockBeginning(d, scanner, c.offset)) {
@@ -279,7 +293,8 @@
 		RubyHeuristicScanner scanner = new RubyHeuristicScanner(d);
 		String indent = "";
 		try {
-			indent = getBlockIndent(d, c, scanner) + fPreferences.getIndent();
+			indent = getBlockIndent(d, c.offset, scanner)
+					+ fPreferences.getIndent();
 		} catch (BadLocationException e) {
 			// there is no enclosing block
 		}
@@ -368,15 +383,15 @@
 	 *         determined
 	 * @throws BadLocationException
 	 */
-	private String getPreviousLineIndent(IDocument d, DocumentCommand c,
+	private String getPreviousLineIndent(IDocument d, int offset,
 			RubyHeuristicScanner scanner) throws BadLocationException {
 		StringBuffer result = new StringBuffer();
 
-		if (c.offset == -1 || d.getLength() == 0)
+		if (offset < 0 || d.getLength() == 0)
 			return result.toString();
 
 		// find start of line
-		int start = scanner.findPrecedingNotEmptyLine(c.offset);
+		int start = scanner.findPrecedingNotEmptyLine(offset);
 		IRegion info = d.getLineInformationOfOffset(start);
 		int end = scanner.findNonWhitespaceForwardInAnyPartition(start, start
 				+ info.getLength());
@@ -390,44 +405,85 @@
 
 	private boolean isBlockClosed(IDocument document, int offset)
 			throws BadLocationException {
+		// TODO: Remove this comment when Ruby parser become able to report
+		// unclosed blocks
+		//
+		// RubyHeuristicScanner scanner = new RubyHeuristicScanner(document);
+		// IRegion sourceRange = scanner.findSurroundingBlock(offset);
+		// if (sourceRange != null) {
+		// String source = document.get(sourceRange.getOffset(), sourceRange
+		// .getLength());
+		// char[] buffer = source.toCharArray();
+		//
+		// SyntaxErrorListener listener = new SyntaxErrorListener();
+		// ISourceParser parser;
+		// try {
+		// parser = DLTKLanguageManager
+		// .getSourceParser(RubyNature.NATURE_ID);
+		// parser.parse(null, buffer, listener);
+		// if (listener.errorOccured())
+		// return false;
+		// } catch (CoreException e) {
+		// DLTKUIPlugin.log(e);
+		// }
+		// }
+		return getBlockBalance(document, offset) <= 0;
+	}
+
+	/**
+	 * Returns the block balance, i.e. zero if the blocks are balanced at
+	 * <code>offset</code>, a negative number if there are more closing than
+	 * opening braces, and a positive number if there are more opening than
+	 * closing braces.
+	 * 
+	 * @param document
+	 * @param offset
+	 * @param partitioning
+	 * @return the block balance
+	 */
+	private static int getBlockBalance(IDocument document, int offset) {
+		if (offset < 1)
+			return -1;
+		if (offset >= document.getLength())
+			return 1;
+
+		int begin = offset;
+		int end = offset - 1;
+
 		RubyHeuristicScanner scanner = new RubyHeuristicScanner(document);
-		IRegion sourceRange = scanner.findSurroundingBlock(offset);
-		if (sourceRange != null) {
-			String source = document.get(sourceRange.getOffset(), sourceRange
-					.getLength());
-			char[] buffer = source.toCharArray();
 
-			SyntaxErrorListener listener = new SyntaxErrorListener();
-			ISourceParser parser;
-			try {
-				parser = DLTKLanguageManager
-						.getSourceParser(RubyNature.NATURE_ID);
-				parser.parse(null, buffer, listener);
-				if (listener.errorOccured())
-					return false;
-			} catch (CoreException e) {
-				DLTKUIPlugin.log(e);
-			}
-		}
-		return true;
-	}
-
-	private static class SyntaxErrorListener implements IProblemReporter {
-		private boolean fError = false;
-
-		public void clearMarkers() {
-		}
-
-		public IMarker reportProblem(IProblem problem) throws CoreException {
-			int id = problem.getID();
-			if ((id & IProblem.Syntax) != 0 || id == IProblem.Unclassified) {
-				fError = true;
-			}
-			return null;
-		}
-
-		public boolean errorOccured() {
-			return fError;
+		while (true) {
+			begin = scanner.findBlockBeginningOffset(begin);
+			end = scanner.findBlockEndingOffset(end + 1);
+			if (begin == RubyHeuristicScanner.NOT_FOUND
+					&& end == RubyHeuristicScanner.NOT_FOUND)
+				return 0;
+			if (begin == RubyHeuristicScanner.NOT_FOUND)
+				return -1;
+			if (end == RubyHeuristicScanner.NOT_FOUND)
+				return 1;
 		}
 	}
+
+	// TODO: Remove this comment when Ruby parser become able to report
+	// unclosed blocks
+	//
+	// private static class SyntaxErrorListener implements IProblemReporter {
+	// private boolean fError = false;
+	//
+	// public void clearMarkers() {
+	// }
+	//
+	// public IMarker reportProblem(IProblem problem) throws CoreException {
+	// int id = problem.getID();
+	// if ((id & IProblem.Syntax) != 0 || id == IProblem.Unclassified) {
+	// fError = true;
+	// }
+	// return null;
+	// }
+	//
+	// public boolean errorOccured() {
+	// return fError;
+	// }
+	// }
 }
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyCodeScanner.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyCodeScanner.java
index 9c8b9a8..4cb59e5 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyCodeScanner.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyCodeScanner.java
@@ -12,6 +12,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.dltk.ruby.internal.ui.text.rules.RubyFloatNumberRule;
 import org.eclipse.dltk.ruby.internal.ui.text.rules.StartWithRule;
 import org.eclipse.dltk.ui.text.AbstractScriptScanner;
 import org.eclipse.dltk.ui.text.IColorManager;
@@ -61,7 +62,7 @@
 		IToken keywordReturn = getToken(IRubyColorConstants.RUBY_KEYWORD_RETURN);
 		IToken comment = getToken(IRubyColorConstants.RUBY_SINGLE_LINE_COMMENT);
 		IToken other = getToken(IRubyColorConstants.RUBY_DEFAULT);
-//		IToken number = getToken(RubyColorConstants.RUBY_NUMBER);
+		IToken number = getToken(IRubyColorConstants.RUBY_NUMBER);
 		
 		IToken classVariable = getToken(IRubyColorConstants.RUBY_CLASS_VARIABLE);
 		IToken instanceVariable = getToken(IRubyColorConstants.RUBY_INSTANCE_VARIABLE);
@@ -72,8 +73,9 @@
 		// Add rule for single line comments.
 		rules.add(new EndOfLineRule("#", comment));
 		// Add generic whitespace rule.
-		rules.add(new WhitespaceRule(new RubyWhitespaceDetector()));
-		// rules.add(new FloatNumberRule(number));
+		rules.add(new WhitespaceRule(new RubyWhitespaceDetector()));		
+		// Add rule for numbers
+		rules.add(new RubyFloatNumberRule(number));
 							
 		// Global Variables
 		rules.add(new StartWithRule(globalVariable, '$') {
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyHeuristicScanner.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyHeuristicScanner.java
index 10560b6..71fa272 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyHeuristicScanner.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyHeuristicScanner.java
@@ -5,17 +5,18 @@
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.dltk.ui.DLTKUIPlugin;
 import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.Region;
 
 public class RubyHeuristicScanner extends ScriptHeuristicScanner implements
 		IRubySymbols {
-	private static final int[] BLOCK_BEGINNINGS_STARTS = { TokenIF, TokenFOR,
+	private static final int[] BLOCK_BEGINNING_KEYWORDS = { TokenIF, TokenFOR,
 			TokenDEF, TokenCASE, TokenCATCH, TokenCLASS, TokenWHILE,
 			TokenBEGIN, TokenUNTIL, TokenUNLESS, TokenMODULE, TokenDO };
 
-	private static final int[] BLOCK_BEGINNINGS_ENDS = { TokenDO, TokenLBRACE };
+	private static final int[] BLOCK_BEGINNING_SYMBOLS = { TokenLBRACE };
 
 	private static final int[] BLOCK_MIDDLES = { TokenELSE, TokenELSIF,
 			TokenENSURE, TokenRESCUE, TokenWHEN };
@@ -23,8 +24,8 @@
 	private static final int[] BLOCK_ENDINGS = { TokenEND, TokenRBRACE };
 
 	static {
-		Arrays.sort(BLOCK_BEGINNINGS_STARTS);
-		Arrays.sort(BLOCK_BEGINNINGS_ENDS);
+		Arrays.sort(BLOCK_BEGINNING_KEYWORDS);
+		Arrays.sort(BLOCK_BEGINNING_SYMBOLS);
 		Arrays.sort(BLOCK_MIDDLES);
 		Arrays.sort(BLOCK_ENDINGS);
 	}
@@ -152,27 +153,32 @@
 		int start = findBlockBeginningOffset(offset);
 		if (start == NOT_FOUND)
 			start = 0;
-		
+
 		int end = findBlockEndingOffset(offset);
 		if (end == NOT_FOUND)
 			end = getDocument().getLength();
-		
+
 		return new Region(start, end - start);
 	}
 
 	public boolean isBlockBeginning(int offset, int bound) {
-		if (Arrays.binarySearch(BLOCK_BEGINNINGS_STARTS, nextToken(offset,
-				bound)) >= 0) {
-			// setting the position to start of the block keyword
-			findNonIdentifierBackward(getPosition(), UNBOUND);
-			setPosition(getPosition() + 1);
-			return true;
-		} else if (Arrays.binarySearch(BLOCK_BEGINNINGS_ENDS, previousToken(
-				bound, offset)) >= 0) {
-			// setting the position to start of the block keyword
-			setPosition(getPosition() + 1);
-			return true;
+		int token = previousToken(bound, offset);
+		while (token != NOT_FOUND) {
+			if (Arrays.binarySearch(BLOCK_BEGINNING_SYMBOLS, token) >= 0)
+				return true;
+
+			if (Arrays.binarySearch(BLOCK_BEGINNING_KEYWORDS, token) >= 0) {
+				int pos = getPosition();
+				token = previousToken(getPosition(), offset);
+				if (token == NOT_FOUND || token == TokenEQUAL) {
+					setPosition(pos + 1);
+					return true;
+				}
+			}
+
+			token = previousToken(getPosition(), offset);
 		}
+
 		return false;
 	}
 
@@ -188,7 +194,14 @@
 	}
 
 	public boolean isBlockEnding(int offset, int bound) {
-		return Arrays.binarySearch(BLOCK_ENDINGS, nextToken(offset, bound)) >= 0; 
+		int token = nextToken(offset, bound);
+		while (token != NOT_FOUND) {
+			if (Arrays.binarySearch(BLOCK_ENDINGS, token) >= 0)
+				return true;
+			token = nextToken(getPosition(), bound);
+		}
+
+		return false;
 	}
 
 	public int findBlockBeginningOffset(int offset) {
@@ -243,4 +256,25 @@
 		}
 		return NOT_FOUND;
 	}
+
+	public int previousTokenAfterInput(int offset, String appended) {
+		try {
+			if (appended.length() == 1) {
+				int token = getGenericToken(appended.charAt(0));
+				if (token != TokenOTHER)
+					return token;
+			}
+
+			IRegion line = getDocument().getLineInformationOfOffset(offset);
+			String content = getDocument().get(line.getOffset(),
+					offset - line.getOffset())
+					+ appended;
+			IDocument newDoc = new Document(content);
+			RubyHeuristicScanner scanner = new RubyHeuristicScanner(newDoc);
+			return scanner.previousToken(content.length(), UNBOUND);
+		} catch (BadLocationException e) {
+			DLTKUIPlugin.log(e);
+		}
+		return NOT_FOUND;
+	}
 }
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyPartitionScanner.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyPartitionScanner.java
index c9fbdf6..50d42db 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyPartitionScanner.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyPartitionScanner.java
@@ -12,6 +12,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.dltk.ruby.internal.ui.text.rules.RubyGlobalVarRule;
+import org.eclipse.dltk.ruby.internal.ui.text.rules.RubyPercentStringRule;
+import org.eclipse.dltk.ruby.internal.ui.text.rules.RubySlashRegexpRule;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.rules.EndOfLineRule;
 import org.eclipse.jface.text.rules.IPredicateRule;
@@ -25,17 +28,20 @@
 	private Token comment;
 	private Token rubyDoc;
 	private Token defaultToken;
-	
+	private Token singleQuoteString;
+
 	/**
 	 * Creates the partitioner and sets up the appropriate rules.
 	 */
 	public RubyPartitionScanner() {
 		super();
-		
+
 		defaultToken = new Token(IDocument.DEFAULT_CONTENT_TYPE);
 
 		string = new Token(IRubyPartitions.RUBY_STRING);
 
+		singleQuoteString = new Token(IRubyPartitions.RUBY_SINGLE_QUOTE_STRING);
+
 		comment = new Token(IRubyPartitions.RUBY_COMMENT);
 
 		rubyDoc = new Token(IRubyPartitions.RUBY_DOC);
@@ -46,14 +52,14 @@
 
 		rules.add(new EndOfLineRule("#", comment));
 
-		rules.add(new MultiLineRule("'", "'", string, '\\', true));
-
 		rules.add(new MultiLineRule("\"", "\"", string, '\\', true));
+		
+		rules.add(new MultiLineRule("'", "'", singleQuoteString, '\\', true));
 
 		rules.add(new RubyPercentStringRule(string, false));
 
 		rules.add(new RubySlashRegexpRule(string));
-		
+
 		rules.add(new RubyGlobalVarRule(defaultToken));
 
 		IPredicateRule[] result = new IPredicateRule[rules.size()];
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySingleQuoteStringScanner.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySingleQuoteStringScanner.java
new file mode 100644
index 0000000..6ebecc8
--- /dev/null
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySingleQuoteStringScanner.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ 
+ *******************************************************************************/
+package org.eclipse.dltk.ruby.internal.ui.text;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.dltk.ruby.internal.ui.text.IRubyColorConstants;
+import org.eclipse.dltk.ui.text.AbstractScriptScanner;
+import org.eclipse.dltk.ui.text.IColorManager;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.rules.WhitespaceRule;
+
+public class RubySingleQuoteStringScanner extends AbstractScriptScanner {
+
+	private static final String[] fgTokenProperties = new String[] { IRubyColorConstants.RUBY_STRING };
+
+	public RubySingleQuoteStringScanner(IColorManager manager,
+			IPreferenceStore store) {
+		super(manager, store);
+
+		initialize();
+	}
+
+	protected String[] getTokenProperties() {
+		return fgTokenProperties;
+	}
+
+	protected List createRules() {
+		List rules = new ArrayList();
+
+		// Add generic whitespace rule.
+		rules.add(new WhitespaceRule(new RubyWhitespaceDetector()));
+		setDefaultReturnToken(getToken(IRubyColorConstants.RUBY_STRING));
+
+		return rules;
+	}
+
+}
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySourceViewerConfiguration.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySourceViewerConfiguration.java
index 385ca8b..86cd40c 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySourceViewerConfiguration.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySourceViewerConfiguration.java
@@ -58,6 +58,8 @@
 
 	private AbstractScriptScanner fStringScanner;
 
+	private AbstractScriptScanner fSingleQuoteStringScanner;
+
 	private AbstractScriptScanner fCommentScanner;
 
 	private AbstractScriptScanner fDocScanner;
@@ -74,7 +76,8 @@
 
 	public String[] getIndentPrefixes(ISourceViewer sourceViewer,
 			String contentType) {
-		RubyPreferenceInterpreter prefs = new RubyPreferenceInterpreter(fPreferenceStore);
+		RubyPreferenceInterpreter prefs = new RubyPreferenceInterpreter(
+				fPreferenceStore);
 		if (prefs.getTabStyle() == TabStyle.SPACES)
 			return new String[] { AutoEditUtils.getNSpaces(prefs
 					.getIndentSize()) };
@@ -94,6 +97,8 @@
 		fCodeScanner = new RubyCodeScanner(getColorManager(), fPreferenceStore);
 		fStringScanner = new RubyStringScanner(getColorManager(),
 				fPreferenceStore);
+		fSingleQuoteStringScanner = new RubySingleQuoteStringScanner(
+				getColorManager(), fPreferenceStore);
 		fCommentScanner = new SingleTokenScriptScanner(getColorManager(),
 				fPreferenceStore, IRubyColorConstants.RUBY_SINGLE_LINE_COMMENT);
 
@@ -130,6 +135,10 @@
 		reconciler.setDamager(dr, IRubyPartitions.RUBY_STRING);
 		reconciler.setRepairer(dr, IRubyPartitions.RUBY_STRING);
 
+		dr = new DefaultDamagerRepairer(getSingleQuoteStringScanner());
+		reconciler.setDamager(dr, IRubyPartitions.RUBY_SINGLE_QUOTE_STRING);
+		reconciler.setRepairer(dr, IRubyPartitions.RUBY_SINGLE_QUOTE_STRING);
+
 		dr = new DefaultDamagerRepairer(getDocScanner());
 		reconciler.setDamager(dr, IRubyPartitions.RUBY_DOC);
 		reconciler.setRepairer(dr, IRubyPartitions.RUBY_DOC);
@@ -141,6 +150,10 @@
 		return reconciler;
 	}
 
+	private ITokenScanner getSingleQuoteStringScanner() {
+		return fSingleQuoteStringScanner;
+	}
+
 	private ITokenScanner getDocScanner() {
 		return fDocScanner;
 	}
@@ -164,6 +177,8 @@
 			fCodeScanner.adaptToPreferenceChange(event);
 		if (fStringScanner.affectsBehavior(event))
 			fStringScanner.adaptToPreferenceChange(event);
+		if (fSingleQuoteStringScanner.affectsBehavior(event))
+			fSingleQuoteStringScanner.adaptToPreferenceChange(event);
 		if (fDocScanner.affectsBehavior(event))
 			fDocScanner.adaptToPreferenceChange(event);
 	}
@@ -180,6 +195,7 @@
 	public boolean affectsTextPresentation(PropertyChangeEvent event) {
 		return fCodeScanner.affectsBehavior(event)
 				|| fStringScanner.affectsBehavior(event)
+				|| fSingleQuoteStringScanner.affectsBehavior(event)
 				|| fDocScanner.affectsBehavior(event);
 	}
 
@@ -292,5 +308,7 @@
 				.setInformationProvider(provider, IRubyPartitions.RUBY_COMMENT);
 		presenter.setInformationProvider(provider, IRubyPartitions.RUBY_DOC);
 		presenter.setInformationProvider(provider, IRubyPartitions.RUBY_STRING);
+		presenter.setInformationProvider(provider,
+				IRubyPartitions.RUBY_SINGLE_QUOTE_STRING);
 	}
 }
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyStringScanner.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyStringScanner.java
index b88b5a3..8f5f0d1 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyStringScanner.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyStringScanner.java
@@ -12,17 +12,19 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.eclipse.dltk.ruby.internal.ui.text.IRubyColorConstants;
 import org.eclipse.dltk.ui.text.AbstractScriptScanner;
 import org.eclipse.dltk.ui.text.IColorManager;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.rules.WhitespaceRule;
+import org.eclipse.jface.text.rules.WordPatternRule;
 
 public class RubyStringScanner extends AbstractScriptScanner {
 
 	private static final String[] fgTokenProperties = new String[] {
-		IRubyColorConstants.RUBY_STRING		
-	};
+			IRubyColorConstants.RUBY_STRING, IRubyColorConstants.RUBY_DEFAULT,
+			IRubyColorConstants.RUBY_CLASS_VARIABLE,
+			IRubyColorConstants.RUBY_GLOBAL_VARIABLE,
+			IRubyColorConstants.RUBY_INSTANCE_VARIABLE };
 
 	public RubyStringScanner(IColorManager manager, IPreferenceStore store) {
 		super(manager, store);
@@ -30,23 +32,26 @@
 		initialize();
 	}
 
-	
 	protected String[] getTokenProperties() {
 		return fgTokenProperties;
 	}
 
-	
 	protected List createRules() {
-		List/*<IRule>*/ rules = new ArrayList/*<IRule>*/();
+		List rules = new ArrayList/* <IRule> */();
 
 		// Add generic whitespace rule.
 		rules.add(new WhitespaceRule(new RubyWhitespaceDetector()));
-		
-		//TODO: Add here % and %{name} variables handling.
-				
+		rules.add(new WordPatternRule(new RubyWordDetector(), "#$", "",
+				getToken(IRubyColorConstants.RUBY_GLOBAL_VARIABLE)));
+		rules.add(new WordPatternRule(new RubyWordDetector(), "#@@", "",
+				getToken(IRubyColorConstants.RUBY_CLASS_VARIABLE)));
+		rules.add(new WordPatternRule(new RubyWordDetector(), "#@", "",
+				getToken(IRubyColorConstants.RUBY_INSTANCE_VARIABLE)));
+//		rules.add(new MultiLineRule("#{", "}",
+//				getToken(IRubyColorConstants.RUBY_DEFAULT)));
+
 		setDefaultReturnToken(getToken(IRubyColorConstants.RUBY_STRING));
 
 		return rules;
 	}
-
 }
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyTextTools.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyTextTools.java
index 86d9541..9106b8c 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyTextTools.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyTextTools.java
@@ -23,8 +23,9 @@
 	private IPartitionTokenScanner fPartitionScanner;
 
 	private final static String[] LEGAL_CONTENT_TYPES = new String[] {
-			IRubyPartitions.RUBY_STRING, IRubyPartitions.RUBY_COMMENT,
-			IRubyPartitions.RUBY_DOC };
+			IRubyPartitions.RUBY_STRING,
+			IRubyPartitions.RUBY_SINGLE_QUOTE_STRING,
+			IRubyPartitions.RUBY_COMMENT, IRubyPartitions.RUBY_DOC };
 
 	public RubyTextTools(boolean autoDisposeOnDisplayDispose) {
 		super(IRubyPartitions.RUBY_PARTITIONING, LEGAL_CONTENT_TYPES,
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/ScriptHeuristicScanner.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/ScriptHeuristicScanner.java
index bfee352..1d53d1e 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/ScriptHeuristicScanner.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/ScriptHeuristicScanner.java
@@ -503,7 +503,7 @@
 		return scanBackward(position, bound, fNonWS);
 	}
 
-	private int getGenericToken(char ch) {
+	protected int getGenericToken(char ch) {
 		switch (ch) {
 		case LBRACE:
 			return TokenLBRACE;
@@ -617,7 +617,7 @@
 			int from, to = pos + 1;
 			pos = findNonIdentifierBackward(pos, bound);
 			if (pos == NOT_FOUND)
-				from = bound == UNBOUND ? 0 : bound + 1;
+				from = bound == UNBOUND ? 0 : bound;
 			else
 				from = pos + 1;
 
@@ -659,34 +659,6 @@
 		}
 		return 0;
 	}
-
-	public int previousTokenAfterInput(int offset, String appended) {
-		try {
-			if (appended.length() == 1) {
-				int token = getGenericToken(appended.charAt(0));
-				if  (token != TokenOTHER)
-					return token;
-			}
-			
-			int lineOffset = fDocument.getLineInformationOfOffset(offset)
-					.getOffset();
-			int token = previousToken(offset, lineOffset);
-			if (token != TokenIDENTIFIER)
-				return token;
-
-			// else
-			int start = getPosition() + 1;
-			int end = findNonIdentifierForward(start, offset);
-			if (end == NOT_FOUND) {
-				end = offset;
-			}
-			String identifier = fDocument.get(start, end - start);
-			return getToken(start, identifier + appended);
-		} catch (BadLocationException e) {
-			DLTKUIPlugin.log(e);
-		}
-		return NOT_FOUND;
-	}
 	
 	/**
 	 * Returns the position of the closing peer character (forward search). Any scopes introduced by opening peers
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/completion/RubyCompletionProposal.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/completion/RubyCompletionProposal.java
index cd0d1c0..3ca659b 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/completion/RubyCompletionProposal.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/completion/RubyCompletionProposal.java
@@ -9,7 +9,10 @@
  *******************************************************************************/
 package org.eclipse.dltk.ruby.internal.ui.text.completion;
 
+import org.eclipse.dltk.ruby.internal.ui.RubyUI;
+import org.eclipse.dltk.ui.PreferenceConstants;
 import org.eclipse.dltk.ui.text.completion.ScriptCompletionProposal;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.swt.graphics.Image;
 
 public class RubyCompletionProposal extends ScriptCompletionProposal {
@@ -36,6 +39,10 @@
 		return false;
 	}
 	
-	
+	protected boolean insertCompletion() {
+		IPreferenceStore preference = RubyUI.getDefault().getPreferenceStore();
+		return preference
+				.getBoolean(PreferenceConstants.CODEASSIST_INSERT_COMPLETION);
+	}
 	
 }
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyFloatNumberRule.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyFloatNumberRule.java
new file mode 100644
index 0000000..155ce9e
--- /dev/null
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyFloatNumberRule.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ 
+ *******************************************************************************/
+package org.eclipse.dltk.ruby.internal.ui.text.rules;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.text.rules.ICharacterScanner;
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.Token;
+
+/**
+ * An implementation of <code>IRule</code> detecting a numerical value.
+ */
+public class RubyFloatNumberRule implements IRule {
+	protected static final int UNDEFINED = -1;
+	protected IToken fToken;
+	protected int fColumn = UNDEFINED;
+
+	public RubyFloatNumberRule(IToken token) {
+		Assert.isNotNull(token);
+		fToken = token;
+	}
+
+	public void setColumnConstraint(int column) {
+		if (column < 0)
+			column = UNDEFINED;
+		fColumn = column;
+	}
+
+	public IToken evaluate(ICharacterScanner scanner) {
+		int c = scanner.read();
+		int p = c;
+		if (Character.isDigit((char) c) || c == '.') {
+			if (fColumn == UNDEFINED || (fColumn == scanner.getColumn() - 1)) {
+				do {
+					p = c;
+					c = scanner.read();
+				} while (Character.isDigit((char) c));
+				if ((c != 'e' && c != 'E')) {
+					scanner.unread();
+				}				
+				if (p == '.') {
+					scanner.unread();
+					return Token.UNDEFINED;
+				}
+				return fToken;
+			}
+		}
+		scanner.unread();
+		return Token.UNDEFINED;
+	}
+}
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyGlobalVarRule.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyGlobalVarRule.java
similarity index 95%
rename from plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyGlobalVarRule.java
rename to plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyGlobalVarRule.java
index edb301f..ea3cd80 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyGlobalVarRule.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyGlobalVarRule.java
@@ -7,7 +7,7 @@
  *
  
  *******************************************************************************/
-package org.eclipse.dltk.ruby.internal.ui.text;
+package org.eclipse.dltk.ruby.internal.ui.text.rules;
 
 import org.eclipse.jface.text.rules.ICharacterScanner;
 import org.eclipse.jface.text.rules.IPredicateRule;
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyPercentStringRule.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyPercentStringRule.java
similarity index 99%
rename from plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyPercentStringRule.java
rename to plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyPercentStringRule.java
index ed19c3d..92c6d9a 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubyPercentStringRule.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubyPercentStringRule.java
@@ -7,7 +7,7 @@
  *
  
  *******************************************************************************/
-package org.eclipse.dltk.ruby.internal.ui.text;
+package org.eclipse.dltk.ruby.internal.ui.text.rules;
 
 import java.util.Arrays;
 import java.util.Comparator;
diff --git a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySlashRegexpRule.java b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubySlashRegexpRule.java
similarity index 95%
rename from plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySlashRegexpRule.java
rename to plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubySlashRegexpRule.java
index 474129e..ab66dfc 100644
--- a/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/RubySlashRegexpRule.java
+++ b/plugins/org.eclipse.dltk.ruby.ui/src/org/eclipse/dltk/ruby/internal/ui/text/rules/RubySlashRegexpRule.java
@@ -7,7 +7,7 @@
  *
  
  *******************************************************************************/
-package org.eclipse.dltk.ruby.internal.ui.text;
+package org.eclipse.dltk.ruby.internal.ui.text.rules;
 
 import org.eclipse.dltk.ruby.core.utils.RubySyntaxUtils;
 import org.eclipse.jface.text.rules.ICharacterScanner;